Chromium Code Reviews| Index: gpu/command_buffer/service/gles2_cmd_decoder.cc |
| diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc |
| index 626e362bc4dddcbe94280aa38c801eb2d15d19df..d938bc881bcc71ade359bf2787521cf177e638d2 100644 |
| --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc |
| +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc |
| @@ -1966,7 +1966,17 @@ class GLES2DecoderImpl : public GLES2Decoder, |
| const char* function_name, GLuint max_vertex_accessed, bool* simulated); |
| void RestoreStateForAttrib(GLuint attrib, bool restore_array_binding); |
| - // If an image is bound to texture, this will call Will/DidUseTexImage |
| + // Calls WillUseTexImage or copies the image to the texture currently bound |
| + // to |textarget| based on the value of |image_state|. The new image state is |
| + // returned. |
| + Texture::ImageState DoWillUseTexImage(GLenum textarget, |
| + gfx::GLImage* image, |
| + Texture::ImageState image_state); |
| + |
| + // Calls DidUseTexImage based on the value of |image_state|. |
| + void DoDidUseTexImage(gfx::GLImage* image, Texture::ImageState image_state); |
| + |
| + // If an image is bound to texture, this will call DoWill/DidUseTexImage |
| // if needed. |
| void DoWillUseTexImageIfNeeded(Texture* texture, GLenum textarget); |
| void DoDidUseTexImageIfNeeded(Texture* texture, GLenum textarget); |
| @@ -7622,18 +7632,56 @@ void GLES2DecoderImpl::PerformanceWarning( |
| std::string("PERFORMANCE WARNING: ") + msg); |
| } |
| +Texture::ImageState GLES2DecoderImpl::DoWillUseTexImage( |
| + GLenum textarget, |
| + gfx::GLImage* image, |
| + Texture::ImageState image_state) { |
| + switch (image_state) { |
| + case Texture::UNBOUND: { |
| + bool rv = image->CopyTexImage(textarget); |
| + DCHECK(rv) << "Both BindTexImage() and CopyTexImage() failed"; |
| + return Texture::COPIED; |
|
Daniele Castagna
2015/10/14 18:40:35
nit: should this be UNBOUND, not that it matters.
reveman
2015/10/14 19:28:01
State should change to COPIED to prevent us from c
|
| + } |
| + case Texture::BOUND: |
| + image->WillUseTexImage(); |
| + return Texture::BOUND; |
| + case Texture::COPIED: |
| + return Texture::COPIED; |
| + } |
| + |
| + NOTREACHED(); |
| + return Texture::UNBOUND; |
| +} |
| + |
| +void GLES2DecoderImpl::DoDidUseTexImage(gfx::GLImage* image, |
| + Texture::ImageState image_state) { |
| + switch (image_state) { |
| + case Texture::BOUND: |
| + image->DidUseTexImage(); |
| + return; |
| + case Texture::UNBOUND: |
| + case Texture::COPIED: |
| + return; |
| + } |
| + |
| + NOTREACHED(); |
| +} |
| + |
| void GLES2DecoderImpl::DoWillUseTexImageIfNeeded( |
| Texture* texture, GLenum textarget) { |
| // Image is already in use if texture is attached to a framebuffer. |
| if (texture && !texture->IsAttachedToFramebuffer()) { |
| - gfx::GLImage* image = texture->GetLevelImage(textarget, 0); |
| + Texture::ImageState image_state; |
| + gfx::GLImage* image = texture->GetLevelImage(textarget, 0, &image_state); |
| if (image) { |
| ScopedGLErrorSuppressor suppressor( |
| "GLES2DecoderImpl::DoWillUseTexImageIfNeeded", |
| GetErrorState()); |
| glBindTexture(textarget, texture->service_id()); |
| - image->WillUseTexImage(); |
| + Texture::ImageState new_image_state = |
| + DoWillUseTexImage(textarget, image, image_state); |
| RestoreCurrentTextureBindings(&state_, textarget); |
| + texture->SetLevelImage(textarget, 0, image, new_image_state); |
| } |
| } |
| } |
| @@ -7642,13 +7690,14 @@ void GLES2DecoderImpl::DoDidUseTexImageIfNeeded( |
| Texture* texture, GLenum textarget) { |
| // Image is still in use if texture is attached to a framebuffer. |
| if (texture && !texture->IsAttachedToFramebuffer()) { |
| - gfx::GLImage* image = texture->GetLevelImage(textarget, 0); |
| + Texture::ImageState image_state; |
| + gfx::GLImage* image = texture->GetLevelImage(textarget, 0, &image_state); |
| if (image) { |
| ScopedGLErrorSuppressor suppressor( |
| "GLES2DecoderImpl::DoDidUseTexImageIfNeeded", |
| GetErrorState()); |
| glBindTexture(textarget, texture->service_id()); |
| - image->DidUseTexImage(); |
| + DoDidUseTexImage(image, image_state); |
| RestoreCurrentTextureBindings(&state_, textarget); |
| } |
| } |
| @@ -7696,13 +7745,17 @@ bool GLES2DecoderImpl::PrepareTexturesForRender() { |
| if (textarget != GL_TEXTURE_CUBE_MAP) { |
| Texture* texture = texture_ref->texture(); |
| - gfx::GLImage* image = texture->GetLevelImage(textarget, 0); |
| + Texture::ImageState image_state; |
| + gfx::GLImage* image = |
| + texture->GetLevelImage(textarget, 0, &image_state); |
| if (image && !texture->IsAttachedToFramebuffer()) { |
| ScopedGLErrorSuppressor suppressor( |
| "GLES2DecoderImpl::PrepareTexturesForRender", GetErrorState()); |
| textures_set = true; |
| glActiveTexture(GL_TEXTURE0 + texture_unit_index); |
| - image->WillUseTexImage(); |
| + Texture::ImageState new_image_state = |
| + DoWillUseTexImage(textarget, image, image_state); |
| + texture->SetLevelImage(textarget, 0, image, new_image_state); |
| continue; |
| } |
| } |
| @@ -7740,13 +7793,14 @@ void GLES2DecoderImpl::RestoreStateForTextures() { |
| if (texture_unit.bind_target != GL_TEXTURE_CUBE_MAP) { |
| Texture* texture = texture_ref->texture(); |
| + Texture::ImageState image_state; |
| gfx::GLImage* image = |
| - texture->GetLevelImage(texture_unit.bind_target, 0); |
| + texture->GetLevelImage(texture_unit.bind_target, 0, &image_state); |
| if (image && !texture->IsAttachedToFramebuffer()) { |
| ScopedGLErrorSuppressor suppressor( |
| "GLES2DecoderImpl::RestoreStateForTextures", GetErrorState()); |
| glActiveTexture(GL_TEXTURE0 + texture_unit_index); |
| - image->DidUseTexImage(); |
| + DoDidUseTexImage(image, image_state); |
| continue; |
| } |
| } |
| @@ -9473,9 +9527,10 @@ error::Error GLES2DecoderImpl::HandleScheduleOverlayPlaneCHROMIUM( |
| "unknown texture"); |
| return error::kNoError; |
| } |
| + Texture::ImageState image_state; |
| gfx::GLImage* image = |
| - ref->texture()->GetLevelImage(ref->texture()->target(), 0); |
| - if (!image) { |
| + ref->texture()->GetLevelImage(ref->texture()->target(), 0, &image_state); |
| + if (!image || image_state != Texture::BOUND) { |
| LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, |
| "glScheduleOverlayPlaneCHROMIUM", |
| "unsupported texture format"); |
| @@ -13091,7 +13146,7 @@ void GLES2DecoderImpl::DoCopyTextureCHROMIUM( |
| int source_width = 0; |
| int source_height = 0; |
| gfx::GLImage* image = |
| - source_texture->GetLevelImage(source_texture->target(), 0); |
| + source_texture->GetLevelImage(source_texture->target(), 0, nullptr); |
| if (image) { |
| gfx::Size size = image->GetSize(); |
| source_width = size.width(); |
| @@ -13195,15 +13250,13 @@ void GLES2DecoderImpl::DoCopyTextureCHROMIUM( |
| ScopedModifyPixels modify(dest_texture_ref); |
| - // Try using GLImage::CopyTexSubImage when possible. |
| + // Try using GLImage::CopyTexImage when possible. |
| bool unpack_premultiply_alpha_change = |
| (unpack_premultiply_alpha ^ unpack_unmultiply_alpha) != 0; |
| if (image && !unpack_flip_y && !unpack_premultiply_alpha_change) { |
| glBindTexture(GL_TEXTURE_2D, dest_texture->service_id()); |
| - if (image->CopyTexSubImage(GL_TEXTURE_2D, gfx::Point(0, 0), |
| - gfx::Rect(0, 0, source_width, source_height))) { |
| + if (image->CopyTexImage(GL_TEXTURE_2D)) |
| return; |
| - } |
| } |
| DoWillUseTexImageIfNeeded(source_texture, source_texture->target()); |
| @@ -13255,7 +13308,7 @@ void GLES2DecoderImpl::DoCopySubTextureCHROMIUM( |
| int source_width = 0; |
| int source_height = 0; |
| gfx::GLImage* image = |
| - source_texture->GetLevelImage(source_texture->target(), 0); |
| + source_texture->GetLevelImage(source_texture->target(), 0, nullptr); |
| if (image) { |
| gfx::Size size = image->GetSize(); |
| source_width = size.width(); |
| @@ -13405,7 +13458,7 @@ void GLES2DecoderImpl::DoCompressedCopyTextureCHROMIUM(GLenum target, |
| int source_width = 0; |
| int source_height = 0; |
| gfx::GLImage* image = |
| - source_texture->GetLevelImage(source_texture->target(), 0); |
| + source_texture->GetLevelImage(source_texture->target(), 0, nullptr); |
| if (image) { |
| gfx::Size size = image->GetSize(); |
| source_width = size.width(); |
| @@ -13523,10 +13576,8 @@ void GLES2DecoderImpl::DoCompressedCopyTextureCHROMIUM(GLenum target, |
| true); |
| } |
| - if (image->CopyTexSubImage(GL_TEXTURE_2D, gfx::Point(0, 0), |
| - gfx::Rect(0, 0, source_width, source_height))) { |
| + if (image->CopyTexImage(GL_TEXTURE_2D)) |
| return; |
| - } |
| } |
| TRACE_EVENT0( |
| @@ -13587,7 +13638,7 @@ void GLES2DecoderImpl::DoCompressedCopySubTextureCHROMIUM(GLenum target, |
| int source_width = 0; |
| int source_height = 0; |
| gfx::GLImage* image = |
| - source_texture->GetLevelImage(source_texture->target(), 0); |
| + source_texture->GetLevelImage(source_texture->target(), 0, nullptr); |
| if (image) { |
| gfx::Size size = image->GetSize(); |
| source_width = size.width(); |
| @@ -13718,11 +13769,10 @@ void GLES2DecoderImpl::DoCompressedCopySubTextureCHROMIUM(GLenum target, |
| ScopedModifyPixels modify(dest_texture_ref); |
| // Try using GLImage::CopyTexSubImage when possible. |
| - if (image) { |
| - if (image->CopyTexSubImage(GL_TEXTURE_2D, gfx::Point(xoffset, yoffset), |
| - gfx::Rect(x, y, width, height))) { |
| - return; |
| - } |
| + if (image && |
| + image->CopyTexSubImage(GL_TEXTURE_2D, gfx::Point(xoffset, yoffset), |
| + gfx::Rect(x, y, width, height))) { |
| + return; |
| } |
| TRACE_EVENT0( |
| @@ -14196,31 +14246,39 @@ void GLES2DecoderImpl::DoBindTexImage2DCHROMIUM( |
| return; |
| } |
| - gfx::GLImage* gl_image = image_manager()->LookupImage(image_id); |
| - if (!gl_image) { |
| + gfx::GLImage* image = image_manager()->LookupImage(image_id); |
| + if (!image) { |
| LOCAL_SET_GL_ERROR( |
| GL_INVALID_OPERATION, |
| "glBindTexImage2DCHROMIUM", "no image found with the given ID"); |
| return; |
| } |
| + Texture::ImageState image_state = Texture::UNBOUND; |
| + |
| { |
| ScopedGLErrorSuppressor suppressor( |
| "GLES2DecoderImpl::DoBindTexImage2DCHROMIUM", GetErrorState()); |
| - if (!gl_image->BindTexImage(target)) { |
| - LOCAL_SET_GL_ERROR( |
| - GL_INVALID_OPERATION, |
| - "glBindTexImage2DCHROMIUM", "fail to bind image with the given ID"); |
| - return; |
| - } |
| + |
| + // Note: We fallback to a lazy GLImage::CopyTexImage() call in |
| + // DoWillUseTexImage() when BindTexImage() fails. |
| + if (image->BindTexImage(target)) |
| + image_state = Texture::BOUND; |
| + } |
| + |
| + // GL_TEXTURE_EXTERNAL_OES is not a supported CopyTexImage() target. |
| + if (target == GL_TEXTURE_EXTERNAL_OES && image_state == Texture::UNBOUND) { |
| + LOCAL_SET_GL_ERROR(GL_INVALID_ENUM, "glBindTexImage2DCHROMIUM", |
| + "invalid target"); |
| + return; |
| } |
| - gfx::Size size = gl_image->GetSize(); |
| + gfx::Size size = image->GetSize(); |
| texture_manager()->SetLevelInfo( |
| - texture_ref, target, 0, gl_image->GetInternalFormat(), size.width(), |
| - size.height(), 1, 0, gl_image->GetInternalFormat(), GL_UNSIGNED_BYTE, |
| + texture_ref, target, 0, image->GetInternalFormat(), size.width(), |
| + size.height(), 1, 0, image->GetInternalFormat(), GL_UNSIGNED_BYTE, |
| gfx::Rect(size)); |
| - texture_manager()->SetLevelImage(texture_ref, target, 0, gl_image); |
| + texture_manager()->SetLevelImage(texture_ref, target, 0, image, image_state); |
| } |
| void GLES2DecoderImpl::DoReleaseTexImage2DCHROMIUM( |
| @@ -14238,27 +14296,37 @@ void GLES2DecoderImpl::DoReleaseTexImage2DCHROMIUM( |
| return; |
| } |
| - gfx::GLImage* gl_image = image_manager()->LookupImage(image_id); |
| - if (!gl_image) { |
| + gfx::GLImage* image = image_manager()->LookupImage(image_id); |
| + if (!image) { |
| LOCAL_SET_GL_ERROR( |
| GL_INVALID_OPERATION, |
| "glReleaseTexImage2DCHROMIUM", "no image found with the given ID"); |
| return; |
| } |
| + Texture::ImageState image_state; |
| + |
| // Do nothing when image is not currently bound. |
| - if (texture_ref->texture()->GetLevelImage(target, 0) != gl_image) |
| + if (texture_ref->texture()->GetLevelImage(target, 0, &image_state) != image) |
| return; |
| { |
| ScopedGLErrorSuppressor suppressor( |
| "GLES2DecoderImpl::DoReleaseTexImage2DCHROMIUM", GetErrorState()); |
| - gl_image->ReleaseTexImage(target); |
| + |
| + if (image_state == Texture::BOUND) |
| + image->ReleaseTexImage(target); |
| + |
| + if (image_state == Texture::COPIED) { |
| + // Effectively frees the texture storage without deleting the texture id. |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, |
| + GL_UNSIGNED_BYTE, nullptr); |
| + } |
| } |
| texture_manager()->SetLevelInfo( |
| - texture_ref, target, 0, gl_image->GetInternalFormat(), 0, 0, 1, 0, |
| - gl_image->GetInternalFormat(), GL_UNSIGNED_BYTE, gfx::Rect()); |
| + texture_ref, target, 0, image->GetInternalFormat(), 0, 0, 1, 0, |
| + image->GetInternalFormat(), GL_UNSIGNED_BYTE, gfx::Rect()); |
| } |
| error::Error GLES2DecoderImpl::HandleTraceBeginCHROMIUM( |