@@ -3985,10 +3985,8 @@ void OpenGLDriver::stopCapture(int) {
39853985// Read-back ops
39863986// ------------------------------------------------------------------------------------------------
39873987
3988- void OpenGLDriver::readPixels (Handle<HwRenderTarget> src,
3989- uint32_t const x, uint32_t const y, uint32_t width, uint32_t height,
3990- PixelBufferDescriptor&& p) {
3991- DEBUG_MARKER ()
3988+ void OpenGLDriver::readPixelsFromBoundFramebuffer (uint32_t const x, uint32_t const y,
3989+ uint32_t width, uint32_t height, PixelBufferDescriptor&& p) {
39923990 auto & gl = mContext ;
39933991
39943992 GLenum const glFormat = getFormat (p.format );
@@ -4021,8 +4019,6 @@ void OpenGLDriver::readPixels(Handle<HwRenderTarget> src,
40214019 * of the buffer.
40224020 */
40234021
4024- GLRenderTarget const * s = handle_cast<GLRenderTarget const *>(src);
4025-
40264022 using PBD = PixelBufferDescriptor;
40274023
40284024 // The PBO only needs to accommodate the area we're reading, with alignment.
@@ -4032,7 +4028,6 @@ void OpenGLDriver::readPixels(Handle<HwRenderTarget> src,
40324028 if (UTILS_UNLIKELY (gl.isES2 ())) {
40334029 void * buffer = malloc (pboSize);
40344030 if (buffer) {
4035- gl.bindFramebuffer (GL_FRAMEBUFFER, s->gl .fbo_read ? s->gl .fbo_read : s->gl .fbo );
40364031 glReadPixels (GLint (x), GLint (y), GLint (width), GLint (height), glFormat, glType, buffer);
40374032 CHECK_GL_ERROR ()
40384033
@@ -4056,10 +4051,6 @@ void OpenGLDriver::readPixels(Handle<HwRenderTarget> src,
40564051 }
40574052
40584053#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
4059- // glReadPixel doesn't resolve automatically, but it does with the auto-resolve extension,
4060- // which we're always emulating. So if we have a resolved fbo (fbo_read), use that instead.
4061- gl.bindFramebuffer (GL_READ_FRAMEBUFFER, s->gl .fbo_read ? s->gl .fbo_read : s->gl .fbo );
4062-
40634054 GLuint pbo;
40644055 glGenBuffers (1 , &pbo);
40654056 gl.bindBuffer (GL_PIXEL_PACK_BUFFER, pbo);
@@ -4111,10 +4102,83 @@ void OpenGLDriver::readPixels(Handle<HwRenderTarget> src,
41114102#endif
41124103}
41134104
4105+ void OpenGLDriver::readPixels (Handle<HwRenderTarget> src, uint32_t const x, uint32_t const y,
4106+ uint32_t width, uint32_t height, PixelBufferDescriptor&& p) {
4107+ DEBUG_MARKER ()
4108+ auto & gl = mContext ;
4109+
4110+ GLRenderTarget const * s = handle_cast<GLRenderTarget const *>(src);
4111+
4112+ if (UTILS_UNLIKELY (gl.isES2 ())) {
4113+ gl.bindFramebuffer (GL_FRAMEBUFFER, s->gl .fbo_read ? s->gl .fbo_read : s->gl .fbo );
4114+ readPixelsFromBoundFramebuffer (x, y, width, height, std::move (p));
4115+ return ;
4116+ }
4117+
4118+ #ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
4119+ // glReadPixel doesn't resolve automatically, but it does with the auto-resolve extension,
4120+ // which we're always emulating. So if we have a resolved fbo (fbo_read), use that instead.
4121+ gl.bindFramebuffer (GL_READ_FRAMEBUFFER, s->gl .fbo_read ? s->gl .fbo_read : s->gl .fbo );
4122+ readPixelsFromBoundFramebuffer (x, y, width, height, std::move (p));
4123+ #endif
4124+ }
4125+
41144126void OpenGLDriver::readTexture (Handle<HwTexture> src, uint8_t level, uint16_t layer, uint32_t x,
41154127 uint32_t y, uint32_t width, uint32_t height, PixelBufferDescriptor&& p) {
4116- // TODO: implement readTexture
4128+ DEBUG_MARKER ()
4129+ auto & gl = mContext ;
4130+
4131+ // readTexture() requires GLES 3.0+ features such as GL_READ_FRAMEBUFFER and
4132+ // glFramebufferTextureLayer, so we wrap it in FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2.
4133+ #ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
4134+ if (UTILS_UNLIKELY (gl.isES2 ())) {
4135+ // This is not supported on ES2 (at least not in this driver)
4136+ scheduleDestroy (std::move (p));
4137+ return ;
4138+ }
4139+
4140+ GLTexture const * s = handle_cast<GLTexture*>(src);
4141+ assert_invariant (s);
4142+ assert_invariant (s->target != SamplerType::SAMPLER_3D);
4143+
4144+ GLuint fbo = 0 ;
4145+ glGenFramebuffers (1 , &fbo);
4146+ gl.bindFramebuffer (GL_READ_FRAMEBUFFER, fbo);
4147+
4148+ GLenum const attachment = GL_COLOR_ATTACHMENT0;
4149+
4150+ switch (s->target ) {
4151+ case SamplerType::SAMPLER_2D:
4152+ if (any (s->usage & TextureUsage::SAMPLEABLE)) {
4153+ glFramebufferTexture2D (GL_READ_FRAMEBUFFER, attachment, GL_TEXTURE_2D, s->gl .id ,
4154+ level);
4155+ } else {
4156+ glFramebufferRenderbuffer (GL_READ_FRAMEBUFFER, attachment, GL_RENDERBUFFER,
4157+ s->gl .id );
4158+ }
4159+ break ;
4160+ case SamplerType::SAMPLER_CUBEMAP:
4161+ glFramebufferTexture2D (GL_READ_FRAMEBUFFER, attachment,
4162+ GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer, s->gl .id , level);
4163+ break ;
4164+ case SamplerType::SAMPLER_2D_ARRAY:
4165+ case SamplerType::SAMPLER_CUBEMAP_ARRAY:
4166+ glFramebufferTextureLayer (GL_READ_FRAMEBUFFER, attachment, s->gl .id , level, layer);
4167+ break ;
4168+ default :
4169+ // This should not happen (e.g. 3D textures are excluded)
4170+ break ;
4171+ }
4172+
4173+ CHECK_GL_FRAMEBUFFER_STATUS (GL_READ_FRAMEBUFFER)
4174+
4175+ readPixelsFromBoundFramebuffer (x, y, width, height, std::move (p));
4176+
4177+ gl.unbindFramebuffer (GL_READ_FRAMEBUFFER);
4178+ glDeleteFramebuffers (1 , &fbo);
4179+ #else
41174180 scheduleDestroy (std::move (p));
4181+ #endif
41184182}
41194183
41204184void OpenGLDriver::readBufferSubData (BufferObjectHandle boh,
0 commit comments