title: Fastest way to render 4k video to an OpenGL ES texture?
body: <p>What is the best way for a software process that is decoding 4k (3840x2160@60hz) video on the CPU to render to an OpenGL ES texture?</p>
  
  <p>My current approach is as follows:</p>
  
  <p>Create a Pixel Buffer Object:</p>
  
  <pre><code>glGenBuffers(1, &amp;pbo_id);
  glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_id);
  </code></pre>
  
  <p>Allocate 3840x2160x4 (width x height x bpp) to PBO:</p>
  
  <pre><code>glBufferData(GL_PIXEL_UNPACK_BUFFER, size, NULL, GL_STREAM_DRAW);
  </code></pre>
  
  <p>Map the PBO into client's memory space:</p>
  
  <pre><code>GLubyte *ptr = (GLubyte *)glMapBufferRange(
                                 GL_PIXEL_UNPACK_BUFFER,
                                 0,
                                 size,
                                 GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
  </code></pre>
  
  <p>Decode directly into this memory and flush manually:</p>
  
  <pre><code>glFlushMappedBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, size);
  </code></pre>
  
  <p>It appears I can do this at ~300 frames per second. That seems pretty
  impressive, that's a lot of data.</p>
  
  <p>Create a texture:</p>
  
  <pre><code>glGenTextures(1, &amp;texture_id);
  glBindTexture(GL_TEXTURE_2D, texture_id);
  </code></pre>
  
  <p>Copy PBO into texture:</p>
  
  <pre><code>glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0);
  </code></pre>
  
  <p>This stage is slow and limits performance to ~60 fps.</p>
  
  <p>And render:</p>
  
  <pre><code>glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  </code></pre>
  
  <p>This stage limits performance further to ~40 fps.</p>
  
  <p>Is this the best approach? Is there a better way to get the pixels on screen once in the PBO? 40 frames per second is not fast enough.</p>
  
  <p>notes:</p>
  
  <ul>
  <li><p>Mapping the memory into the client's address space makes integration with the video decode simpler and the transfer to GPU doesn't have to wait for the entire frame to be decoded.</p></li>
  <li><p>I could use two or more PBOs. Decode the current frame into one PBO and then render/display the previous frame's PBO to take advantage of the asynchronous nature of writing to a PBO? However, this would add an extra frame of decode latency which I am very keen to avoid.</p></li>
  <li><p>My vertex and fragment shaders are for now straight pass-through. I have no locking/fencing atm but obviously will require it later.</p></li>
  <li><p>I am using Linux, Wayland and EGL. Using DRM Dumb Buffers directly I can achieve ~200 fps.</p></li>
  </ul>