| 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 e0805e64a2f90fed493f674fc2cb489364f8535c..d4e905699295ef341096c94519ef4c0ec6670ebf 100644
|
| --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
|
| +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
|
| @@ -1298,9 +1298,14 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient {
|
| GLenum gl_error,
|
| const char* func_name);
|
|
|
| - bool CheckBoundDrawFramebufferValid(const char* func_name);
|
| + bool CheckBoundDrawFramebufferValid(
|
| + const char* func_name,
|
| + bool may_need_workaround);
|
| // Generates |gl_error| if the bound read fbo is incomplete.
|
| - bool CheckBoundReadFramebufferValid(const char* func_name, GLenum gl_error);
|
| + bool CheckBoundReadFramebufferValid(
|
| + const char* func_name,
|
| + GLenum gl_error,
|
| + bool may_need_workaround);
|
| // This is only used by DoBlitFramebufferCHROMIUM which operates read/draw
|
| // framebuffer at the same time.
|
| bool CheckBoundFramebufferValid(const char* func_name);
|
| @@ -1431,6 +1436,18 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient {
|
| void DoBufferSubData(
|
| GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid * data);
|
|
|
| + // If the specified draw buffer have no image, return true.
|
| + // Otherwise, return false.
|
| + bool SpecifiedDrawBufferHasNoImage(GLint ii);
|
| +
|
| + // A workaround to adjust read buffer and draw buffers to GL_NONE
|
| + // if the specified read buffer or draw buffers have missing images.
|
| + // Return false if read buffer has no image or all of the draw buffers
|
| + // have no image after adjustment. Then we can generate
|
| + // INVALID_OPERATION or return directly in the callers accordingly.
|
| + bool AdjustColorBufferAttachmentsIfNecessary(
|
| + bool read, bool draw);
|
| +
|
| // Wrapper for glCheckFramebufferStatus
|
| GLenum DoCheckFramebufferStatus(GLenum target);
|
|
|
| @@ -4274,7 +4291,16 @@ bool GLES2DecoderImpl::CheckFramebufferValid(
|
| return true;
|
| }
|
|
|
| -bool GLES2DecoderImpl::CheckBoundDrawFramebufferValid(const char* func_name) {
|
| +bool GLES2DecoderImpl::CheckBoundDrawFramebufferValid(
|
| + const char* func_name, bool may_need_workaround) {
|
| + if (may_need_workaround &&
|
| + workarounds().read_draw_buffers_missing_image &&
|
| + SupportsDrawBuffers() &&
|
| + framebuffer_state_.clear_state_dirty) {
|
| + if (!AdjustColorBufferAttachmentsIfNecessary(false, true)) {
|
| + return false;
|
| + }
|
| + }
|
| GLenum target = features().chromium_framebuffer_multisample ?
|
| GL_DRAW_FRAMEBUFFER : GL_FRAMEBUFFER;
|
| Framebuffer* framebuffer = GetFramebufferInfoForTarget(target);
|
| @@ -4298,7 +4324,17 @@ bool GLES2DecoderImpl::CheckBoundDrawFramebufferValid(const char* func_name) {
|
| }
|
|
|
| bool GLES2DecoderImpl::CheckBoundReadFramebufferValid(
|
| - const char* func_name, GLenum gl_error) {
|
| + const char* func_name, GLenum gl_error, bool may_need_workaround) {
|
| + if (may_need_workaround &&
|
| + workarounds().read_draw_buffers_missing_image &&
|
| + SupportsDrawBuffers() &&
|
| + framebuffer_state_.clear_state_dirty) {
|
| + if (!AdjustColorBufferAttachmentsIfNecessary(true, false)) {
|
| + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, func_name,
|
| + "no valid color image");
|
| + return false;
|
| + }
|
| + }
|
| GLenum target = features().chromium_framebuffer_multisample ?
|
| GL_READ_FRAMEBUFFER : GL_FRAMEBUFFER;
|
| Framebuffer* framebuffer = GetFramebufferInfoForTarget(target);
|
| @@ -6167,7 +6203,8 @@ bool GLES2DecoderImpl::GetHelper(
|
| // GL error occur, we fall back to our internal implementation.
|
| *num_written = 1;
|
| if (!CheckBoundReadFramebufferValid("glGetIntegerv",
|
| - GL_INVALID_OPERATION)) {
|
| + GL_INVALID_OPERATION,
|
| + false)) {
|
| if (params) {
|
| *params = 0;
|
| }
|
| @@ -7213,7 +7250,20 @@ error::Error GLES2DecoderImpl::HandleDeleteProgram(
|
| error::Error GLES2DecoderImpl::DoClear(GLbitfield mask) {
|
| const char* func_name = "glClear";
|
| DCHECK(!ShouldDeferDraws());
|
| - if (CheckBoundDrawFramebufferValid(func_name)) {
|
| + if ((mask & GL_COLOR_BUFFER_BIT) != 0 &&
|
| + workarounds().read_draw_buffers_missing_image &&
|
| + SupportsDrawBuffers() &&
|
| + framebuffer_state_.clear_state_dirty) {
|
| + if (!AdjustColorBufferAttachmentsIfNecessary(false, true)) {
|
| + if ((mask & GL_DEPTH_BUFFER_BIT) == 0 &&
|
| + (mask & GL_STENCIL_BUFFER_BIT) == 0) {
|
| + return error::kNoError;
|
| + } else {
|
| + mask &= ~GL_COLOR_BUFFER_BIT;
|
| + }
|
| + }
|
| + }
|
| + if (CheckBoundDrawFramebufferValid(func_name, false)) {
|
| ApplyDirtyState();
|
| if (workarounds().gl_clear_broken) {
|
| if (!BoundFramebufferHasDepthAttachment())
|
| @@ -7240,8 +7290,14 @@ error::Error GLES2DecoderImpl::DoClear(GLbitfield mask) {
|
| void GLES2DecoderImpl::DoClearBufferiv(GLenum buffer,
|
| GLint drawbuffer,
|
| const volatile GLint* value) {
|
| + if (workarounds().read_draw_buffers_missing_image &&
|
| + buffer == GL_COLOR &&
|
| + framebuffer_state_.clear_state_dirty) {
|
| + if (SpecifiedDrawBufferHasNoImage(drawbuffer))
|
| + return;
|
| + }
|
| const char* func_name = "glClearBufferiv";
|
| - if (!CheckBoundDrawFramebufferValid(func_name))
|
| + if (!CheckBoundDrawFramebufferValid(func_name, false))
|
| return;
|
| ApplyDirtyState();
|
|
|
| @@ -7275,8 +7331,14 @@ void GLES2DecoderImpl::DoClearBufferiv(GLenum buffer,
|
| void GLES2DecoderImpl::DoClearBufferuiv(GLenum buffer,
|
| GLint drawbuffer,
|
| const volatile GLuint* value) {
|
| + if (workarounds().read_draw_buffers_missing_image &&
|
| + buffer == GL_COLOR &&
|
| + framebuffer_state_.clear_state_dirty) {
|
| + if (SpecifiedDrawBufferHasNoImage(drawbuffer))
|
| + return;
|
| + }
|
| const char* func_name = "glClearBufferuiv";
|
| - if (!CheckBoundDrawFramebufferValid(func_name))
|
| + if (!CheckBoundDrawFramebufferValid(func_name, false))
|
| return;
|
| ApplyDirtyState();
|
|
|
| @@ -7299,8 +7361,14 @@ void GLES2DecoderImpl::DoClearBufferuiv(GLenum buffer,
|
| void GLES2DecoderImpl::DoClearBufferfv(GLenum buffer,
|
| GLint drawbuffer,
|
| const volatile GLfloat* value) {
|
| + if (workarounds().read_draw_buffers_missing_image &&
|
| + buffer == GL_COLOR &&
|
| + framebuffer_state_.clear_state_dirty) {
|
| + if (SpecifiedDrawBufferHasNoImage(drawbuffer))
|
| + return;
|
| + }
|
| const char* func_name = "glClearBufferfv";
|
| - if (!CheckBoundDrawFramebufferValid(func_name))
|
| + if (!CheckBoundDrawFramebufferValid(func_name, false))
|
| return;
|
| ApplyDirtyState();
|
|
|
| @@ -7334,7 +7402,7 @@ void GLES2DecoderImpl::DoClearBufferfv(GLenum buffer,
|
| void GLES2DecoderImpl::DoClearBufferfi(
|
| GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {
|
| const char* func_name = "glClearBufferfi";
|
| - if (!CheckBoundDrawFramebufferValid(func_name))
|
| + if (!CheckBoundDrawFramebufferValid(func_name, false))
|
| return;
|
| ApplyDirtyState();
|
|
|
| @@ -7532,6 +7600,55 @@ void GLES2DecoderImpl::RestoreClearState() {
|
| state_.scissor_height);
|
| }
|
|
|
| +bool GLES2DecoderImpl::SpecifiedDrawBufferHasNoImage(GLint ii) {
|
| + if (ii < 0 || ii >= static_cast<GLint>(group_->max_draw_buffers()))
|
| + return false;
|
| + const Framebuffer* framebuffer =
|
| + GetFramebufferInfoForTarget(GL_DRAW_FRAMEBUFFER);
|
| + if (!framebuffer)
|
| + return false;
|
| + GLenum attachment = static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + ii);
|
| + if (!(framebuffer->GetAttachment(attachment)) &&
|
| + framebuffer->ColorBuffersHaveImage()) {
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +bool GLES2DecoderImpl::AdjustColorBufferAttachmentsIfNecessary(
|
| + bool read, bool draw) {
|
| + DCHECK(workarounds().read_draw_buffers_missing_image &&
|
| + SupportsDrawBuffers() &&
|
| + framebuffer_state_.clear_state_dirty);
|
| + if (read) {
|
| + const Framebuffer* framebuffer =
|
| + GetFramebufferInfoForTarget(GL_READ_FRAMEBUFFER);
|
| + if (framebuffer &&
|
| + framebuffer->ReadBufferHasNoImage() &&
|
| + framebuffer->ColorBuffersHaveImage()) {
|
| + glReadBuffer(GL_NONE);
|
| + return false;
|
| + }
|
| + } else {
|
| + GLsizei num = 0;
|
| + GLsizei total = group_->max_draw_buffers();
|
| + GLenum safe_bufs[16];
|
| + for (int i = 0; i < 16; ++i)
|
| + safe_bufs[i] = GL_NONE;
|
| + const Framebuffer* framebuffer =
|
| + GetFramebufferInfoForTarget(GL_DRAW_FRAMEBUFFER);
|
| + if (framebuffer &&
|
| + framebuffer->DrawBuffersHaveMissingImage(&num, safe_bufs) &&
|
| + framebuffer->ColorBuffersHaveImage()) {
|
| + glDrawBuffersARB(total, safe_bufs);
|
| + if (num == 0) {
|
| + return false;
|
| + }
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| GLenum GLES2DecoderImpl::DoCheckFramebufferStatus(GLenum target) {
|
| Framebuffer* framebuffer =
|
| GetFramebufferInfoForTarget(target);
|
| @@ -7542,6 +7659,21 @@ GLenum GLES2DecoderImpl::DoCheckFramebufferStatus(GLenum target) {
|
| if (completeness != GL_FRAMEBUFFER_COMPLETE) {
|
| return completeness;
|
| }
|
| +
|
| + bool has_image = true;
|
| + if (workarounds().read_draw_buffers_missing_image &&
|
| + SupportsDrawBuffers() &&
|
| + framebuffer_state_.clear_state_dirty) {
|
| + if (target == GL_READ_FRAMEBUFFER) {
|
| + has_image = AdjustColorBufferAttachmentsIfNecessary(true, false);
|
| + } else {
|
| + has_image = AdjustColorBufferAttachmentsIfNecessary(false, true);
|
| + }
|
| + if (!has_image) {
|
| + return GL_FRAMEBUFFER_COMPLETE;
|
| + }
|
| + }
|
| +
|
| return framebuffer->GetStatus(texture_manager(), target);
|
| }
|
|
|
| @@ -7832,6 +7964,19 @@ void GLES2DecoderImpl::DoBlitFramebufferCHROMIUM(
|
| const char* func_name = "glBlitFramebufferCHROMIUM";
|
| DCHECK(!ShouldDeferReads() && !ShouldDeferDraws());
|
|
|
| + if (workarounds().read_draw_buffers_missing_image &&
|
| + (mask & GL_COLOR_BUFFER_BIT) != 0 &&
|
| + SupportsDrawBuffers() &&
|
| + framebuffer_state_.clear_state_dirty) {
|
| + if (!AdjustColorBufferAttachmentsIfNecessary(false, true)) {
|
| + return;
|
| + }
|
| + if (!AdjustColorBufferAttachmentsIfNecessary(true, false)) {
|
| + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, func_name,
|
| + "no valid color image");
|
| + return;
|
| + }
|
| + }
|
| if (!CheckBoundFramebufferValid(func_name)) {
|
| return;
|
| }
|
| @@ -9806,7 +9951,7 @@ error::Error GLES2DecoderImpl::DoDrawArrays(
|
| LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "primcount < 0");
|
| return error::kNoError;
|
| }
|
| - if (!CheckBoundDrawFramebufferValid(function_name)) {
|
| + if (!CheckBoundDrawFramebufferValid(function_name, true)) {
|
| return error::kNoError;
|
| }
|
| // We have to check this here because the prototype for glDrawArrays
|
| @@ -9970,7 +10115,7 @@ error::Error GLES2DecoderImpl::DoDrawElements(const char* function_name,
|
| return error::kNoError;
|
| }
|
|
|
| - if (!CheckBoundDrawFramebufferValid(function_name)) {
|
| + if (!CheckBoundDrawFramebufferValid(function_name, true)) {
|
| return error::kNoError;
|
| }
|
|
|
| @@ -11195,8 +11340,9 @@ error::Error GLES2DecoderImpl::HandleReadPixels(uint32_t immediate_data_size,
|
| return error::kNoError;
|
| }
|
|
|
| - if (!CheckBoundReadFramebufferValid(
|
| - func_name, GL_INVALID_FRAMEBUFFER_OPERATION)) {
|
| + if (!CheckBoundReadFramebufferValid(func_name,
|
| + GL_INVALID_FRAMEBUFFER_OPERATION,
|
| + true)) {
|
| return error::kNoError;
|
| }
|
| GLenum src_internal_format = GetBoundReadFramebufferInternalFormat();
|
| @@ -13821,7 +13967,8 @@ void GLES2DecoderImpl::DoCopyTexImage2D(
|
| }
|
|
|
| if (!CheckBoundReadFramebufferValid(func_name,
|
| - GL_INVALID_FRAMEBUFFER_OPERATION)) {
|
| + GL_INVALID_FRAMEBUFFER_OPERATION,
|
| + true)) {
|
| return;
|
| }
|
|
|
| @@ -14068,7 +14215,8 @@ void GLES2DecoderImpl::DoCopyTexSubImage2D(
|
| }
|
|
|
| if (!CheckBoundReadFramebufferValid(func_name,
|
| - GL_INVALID_FRAMEBUFFER_OPERATION)) {
|
| + GL_INVALID_FRAMEBUFFER_OPERATION,
|
| + true)) {
|
| return;
|
| }
|
|
|
| @@ -14184,7 +14332,8 @@ void GLES2DecoderImpl::DoCopyTexSubImage3D(
|
| }
|
|
|
| if (!CheckBoundReadFramebufferValid(func_name,
|
| - GL_INVALID_FRAMEBUFFER_OPERATION)) {
|
| + GL_INVALID_FRAMEBUFFER_OPERATION,
|
| + true)) {
|
| return;
|
| }
|
|
|
| @@ -18197,7 +18346,7 @@ error::Error GLES2DecoderImpl::HandleStencilFillPathCHROMIUM(
|
| // This holds for other rendering functions, too.
|
| return error::kNoError;
|
| }
|
| - if (!CheckBoundDrawFramebufferValid(kFunctionName))
|
| + if (!CheckBoundDrawFramebufferValid(kFunctionName, false))
|
| return error::kNoError;
|
| ApplyDirtyState();
|
| glStencilFillPathNV(service_id, fill_mode, mask);
|
| @@ -18220,7 +18369,7 @@ error::Error GLES2DecoderImpl::HandleStencilStrokePathCHROMIUM(
|
| }
|
| GLint reference = static_cast<GLint>(c.reference);
|
| GLuint mask = static_cast<GLuint>(c.mask);
|
| - if (!CheckBoundDrawFramebufferValid(kFunctionName))
|
| + if (!CheckBoundDrawFramebufferValid(kFunctionName, false))
|
| return error::kNoError;
|
| ApplyDirtyState();
|
| glStencilStrokePathNV(service_id, reference, mask);
|
| @@ -18245,7 +18394,7 @@ error::Error GLES2DecoderImpl::HandleCoverFillPathCHROMIUM(
|
| GLuint service_id = 0;
|
| if (!path_manager()->GetPath(static_cast<GLuint>(c.path), &service_id))
|
| return error::kNoError;
|
| - if (!CheckBoundDrawFramebufferValid(kFunctionName))
|
| + if (!CheckBoundDrawFramebufferValid(kFunctionName, false))
|
| return error::kNoError;
|
| ApplyDirtyState();
|
| glCoverFillPathNV(service_id, cover_mode);
|
| @@ -18271,7 +18420,7 @@ error::Error GLES2DecoderImpl::HandleCoverStrokePathCHROMIUM(
|
| if (!path_manager()->GetPath(static_cast<GLuint>(c.path), &service_id))
|
| return error::kNoError;
|
|
|
| - if (!CheckBoundDrawFramebufferValid(kFunctionName))
|
| + if (!CheckBoundDrawFramebufferValid(kFunctionName, false))
|
| return error::kNoError;
|
| ApplyDirtyState();
|
| glCoverStrokePathNV(service_id, cover_mode);
|
| @@ -18301,7 +18450,7 @@ error::Error GLES2DecoderImpl::HandleStencilThenCoverFillPathCHROMIUM(
|
| if (!path_manager()->GetPath(static_cast<GLuint>(c.path), &service_id))
|
| return error::kNoError;
|
|
|
| - if (!CheckBoundDrawFramebufferValid(kFunctionName))
|
| + if (!CheckBoundDrawFramebufferValid(kFunctionName, false))
|
| return error::kNoError;
|
| ApplyDirtyState();
|
| glStencilThenCoverFillPathNV(service_id, fill_mode, mask, cover_mode);
|
| @@ -18331,7 +18480,7 @@ error::Error GLES2DecoderImpl::HandleStencilThenCoverStrokePathCHROMIUM(
|
| GLint reference = static_cast<GLint>(c.reference);
|
| GLuint mask = static_cast<GLuint>(c.mask);
|
|
|
| - if (!CheckBoundDrawFramebufferValid(kFunctionName))
|
| + if (!CheckBoundDrawFramebufferValid(kFunctionName, false))
|
| return error::kNoError;
|
| ApplyDirtyState();
|
| glStencilThenCoverStrokePathNV(service_id, reference, mask, cover_mode);
|
| @@ -18371,7 +18520,7 @@ error::Error GLES2DecoderImpl::HandleStencilFillPathInstancedCHROMIUM(
|
| if (!v.GetTransforms(c, num_paths, transform_type, &transforms))
|
| return v.error();
|
|
|
| - if (!CheckBoundDrawFramebufferValid(kFunctionName))
|
| + if (!CheckBoundDrawFramebufferValid(kFunctionName, false))
|
| return error::kNoError;
|
| ApplyDirtyState();
|
| glStencilFillPathInstancedNV(num_paths, GL_UNSIGNED_INT, paths.get(), 0,
|
| @@ -18411,7 +18560,7 @@ error::Error GLES2DecoderImpl::HandleStencilStrokePathInstancedCHROMIUM(
|
|
|
| GLint reference = static_cast<GLint>(c.reference);
|
| GLuint mask = static_cast<GLuint>(c.mask);
|
| - if (!CheckBoundDrawFramebufferValid(kFunctionName))
|
| + if (!CheckBoundDrawFramebufferValid(kFunctionName, false))
|
| return error::kNoError;
|
| ApplyDirtyState();
|
| glStencilStrokePathInstancedNV(num_paths, GL_UNSIGNED_INT, paths.get(), 0,
|
| @@ -18450,7 +18599,7 @@ error::Error GLES2DecoderImpl::HandleCoverFillPathInstancedCHROMIUM(
|
| if (!v.GetTransforms(c, num_paths, transform_type, &transforms))
|
| return v.error();
|
|
|
| - if (!CheckBoundDrawFramebufferValid(kFunctionName))
|
| + if (!CheckBoundDrawFramebufferValid(kFunctionName, false))
|
| return error::kNoError;
|
| ApplyDirtyState();
|
| glCoverFillPathInstancedNV(num_paths, GL_UNSIGNED_INT, paths.get(), 0,
|
| @@ -18490,7 +18639,7 @@ error::Error GLES2DecoderImpl::HandleCoverStrokePathInstancedCHROMIUM(
|
| if (!v.GetTransforms(c, num_paths, transform_type, &transforms))
|
| return v.error();
|
|
|
| - if (!CheckBoundDrawFramebufferValid(kFunctionName))
|
| + if (!CheckBoundDrawFramebufferValid(kFunctionName, false))
|
| return error::kNoError;
|
| ApplyDirtyState();
|
| glCoverStrokePathInstancedNV(num_paths, GL_UNSIGNED_INT, paths.get(), 0,
|
| @@ -18533,7 +18682,7 @@ error::Error GLES2DecoderImpl::HandleStencilThenCoverFillPathInstancedCHROMIUM(
|
| if (!v.GetTransforms(c, num_paths, transform_type, &transforms))
|
| return v.error();
|
|
|
| - if (!CheckBoundDrawFramebufferValid(kFunctionName))
|
| + if (!CheckBoundDrawFramebufferValid(kFunctionName, false))
|
| return error::kNoError;
|
| ApplyDirtyState();
|
| glStencilThenCoverFillPathInstancedNV(num_paths, GL_UNSIGNED_INT, paths.get(),
|
| @@ -18577,7 +18726,7 @@ GLES2DecoderImpl::HandleStencilThenCoverStrokePathInstancedCHROMIUM(
|
| GLint reference = static_cast<GLint>(c.reference);
|
| GLuint mask = static_cast<GLuint>(c.mask);
|
|
|
| - if (!CheckBoundDrawFramebufferValid(kFunctionName))
|
| + if (!CheckBoundDrawFramebufferValid(kFunctionName, false))
|
| return error::kNoError;
|
| ApplyDirtyState();
|
| glStencilThenCoverStrokePathInstancedNV(
|
|
|