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 6df7f6a2f816a89bb6e37149101e0a60c27a2da4..8b9ad5bb70bf0ca55a4519189207168e4876e78d 100644 |
| --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc |
| +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc |
| @@ -1366,6 +1366,16 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient { |
| // of the draw operation are the same. |
| bool CheckDrawingFeedbackLoops(); |
| + // Checks if a draw buffer's format and its corresponding fragment shader |
| + // output's type are compatible, i.e., a signed integer typed variable is |
| + // incompatible with a float or unsigned integer buffer. |
| + // If incompaticle, generates an INVALID_OPERATION to avoid undefined buffer |
| + // contents and return false. |
| + // Otherwise, filter out the draw buffers that are not written to but are not |
| + // NONE through DrawBuffers, to be on the safe side; set |adjusted| to true |
| + // if such adjustments happen. Return true. |
| + bool ValidateAndAdjustDrawBuffers(const char* function_name, bool* adjusted); |
| + |
| // Checks if |api_type| is valid for the given uniform |
| // If the api type is not valid generates the appropriate GL |
| // error. Returns true if |api_type| is valid for the uniform |
| @@ -7096,7 +7106,7 @@ void GLES2DecoderImpl::ClearUnclearedAttachments( |
| if (cleared_int_renderbuffers || clear_bits) { |
| if (reset_draw_buffers) |
| - framebuffer->RestoreDrawBuffersAfterClear(); |
| + framebuffer->RestoreDrawBuffers(); |
| RestoreClearState(); |
| if (target == GL_READ_FRAMEBUFFER && draw_framebuffer != framebuffer) { |
| GLuint service_id = draw_framebuffer ? draw_framebuffer->service_id() : |
| @@ -8026,6 +8036,58 @@ bool GLES2DecoderImpl::CheckDrawingFeedbackLoops() { |
| return false; |
| } |
| +bool GLES2DecoderImpl::ValidateAndAdjustDrawBuffers( |
| + const char* function_name, bool* adjusted) { |
| + bool validation = true; |
| + bool my_adjusted = false; |
| + switch (feature_info_->context_type()) { |
| + case CONTEXT_TYPE_OPENGLES2: |
| + case CONTEXT_TYPE_WEBGL1: |
| + // Int and unsigned int formats are not available in ES2/WebGL1. |
| + validation = false; |
| + break; |
| + default: |
| + break; |
| + } |
| + Framebuffer* framebuffer = framebuffer_state_.bound_draw_framebuffer.get(); |
| + if (!state_.current_program.get() || !framebuffer) { |
| + return true; |
| + } |
| + const std::vector<ShaderVariableBaseType>& fragment_output_base_types = |
| + state_.current_program->GetFragmentOutputBaseTypes(); |
| + const std::vector<ShaderVariableBaseType>& color_attachment_base_types = |
| + framebuffer->GetColorAttachmentBaseTypes(); |
| + DCHECK_EQ(fragment_output_base_types.size(), |
| + color_attachment_base_types.size()); |
| + size_t count = color_attachment_base_types.size(); |
| + std::unique_ptr<GLenum[]> adjusted_draw_buffers(new GLenum[count]); |
| + for (size_t ii = 0; ii < count; ++ii) { |
| + adjusted_draw_buffers[ii] = |
| + framebuffer->GetDrawBuffer(GL_DRAW_BUFFER0 + ii); |
| + if (adjusted_draw_buffers[ii] == GL_NONE) |
| + continue; |
| + if (fragment_output_base_types[ii] == SHADER_VARIABLE_UNDEFINED_TYPE) { |
| + adjusted_draw_buffers[ii] = GL_NONE; |
|
Corentin Wallez
2016/07/13 14:50:07
This looks like it will be doing an allocation for
|
| + my_adjusted = true; |
| + continue; |
| + } |
| + if (!validation) |
| + continue; |
| + if (color_attachment_base_types[ii] == SHADER_VARIABLE_UNDEFINED_TYPE) |
| + continue; |
| + if (fragment_output_base_types[ii] != color_attachment_base_types[ii]) { |
| + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name, |
| + "buffer format and fragment output variable type incompatible"); |
| + return false; |
| + } |
| + } |
| + if (my_adjusted) { |
| + glDrawBuffersARB(count, adjusted_draw_buffers.get()); |
| + } |
| + *adjusted = my_adjusted; |
| + return true; |
| +} |
| + |
| bool GLES2DecoderImpl::CheckUniformForApiType( |
| const Program::UniformInfo* info, |
| const char* function_name, |
| @@ -9053,11 +9115,19 @@ error::Error GLES2DecoderImpl::DoDrawArrays( |
| primcount)) { |
| bool textures_set = !PrepareTexturesForRender(); |
| ApplyDirtyState(); |
| + bool adjusted = false; |
| + if (!ValidateAndAdjustDrawBuffers(function_name, &adjusted)) { |
| + return error::kNoError; |
| + } |
| if (!instanced) { |
| glDrawArrays(mode, first, count); |
| } else { |
| glDrawArraysInstancedANGLE(mode, first, count, primcount); |
| } |
| + if (adjusted) { |
| + DCHECK(framebuffer_state_.bound_draw_framebuffer.get()); |
| + framebuffer_state_.bound_draw_framebuffer->RestoreDrawBuffers(); |
| + } |
| if (textures_set) { |
| RestoreStateForTextures(); |
| } |
| @@ -9194,14 +9264,16 @@ error::Error GLES2DecoderImpl::DoDrawElements(const char* function_name, |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); |
| indices = element_array_buffer->GetRange(offset, 0); |
| } |
| - |
| + bool adjusted = false; |
| + if (!ValidateAndAdjustDrawBuffers(function_name, &adjusted)) { |
| + return error::kNoError; |
| + } |
| if (state_.enable_flags.primitive_restart_fixed_index && |
| feature_info_->feature_flags(). |
| emulate_primitive_restart_fixed_index) { |
| glEnable(GL_PRIMITIVE_RESTART); |
| buffer_manager()->SetPrimitiveRestartFixedIndexIfNecessary(type); |
| } |
| - |
| if (!instanced) { |
| glDrawElements(mode, count, type, indices); |
| } else { |
| @@ -9212,12 +9284,14 @@ error::Error GLES2DecoderImpl::DoDrawElements(const char* function_name, |
| emulate_primitive_restart_fixed_index) { |
| glDisable(GL_PRIMITIVE_RESTART); |
| } |
| - |
| + if (adjusted) { |
| + DCHECK(framebuffer_state_.bound_draw_framebuffer.get()); |
| + framebuffer_state_.bound_draw_framebuffer->RestoreDrawBuffers(); |
| + } |
| if (used_client_side_array) { |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, |
| element_array_buffer->service_id()); |
| } |
| - |
| if (textures_set) { |
| RestoreStateForTextures(); |
| } |