// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "gpu/command_buffer/service/gles2_cmd_clear_framebuffer.h" #include "base/basictypes.h" #include "gpu/command_buffer/service/gl_utils.h" #include "gpu/command_buffer/service/gles2_cmd_decoder.h" #include "ui/gfx/geometry/size.h" namespace { #define SHADER(src) \ "#ifdef GL_ES\n" \ "precision mediump float;\n" \ "#endif\n" #src const char* g_vertex_shader_source = { SHADER( uniform float u_clear_depth; attribute vec4 a_position; void main(void) { gl_Position = vec4(a_position.x, a_position.y, u_clear_depth, 1.0); } ), }; const char* g_fragment_shader_source = { SHADER( uniform vec4 u_clear_color; void main(void) { gl_FragColor = u_clear_color; } ), }; void CompileShader(GLuint shader, const char* shader_source) { glShaderSource(shader, 1, &shader_source, 0); glCompileShader(shader); #if DCHECK_IS_ON() GLint compile_status = GL_FALSE; glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status); if (GL_TRUE != compile_status) { char buffer[1024]; GLsizei length = 0; glGetShaderInfoLog(shader, sizeof(buffer), &length, buffer); std::string log(buffer, length); DLOG(ERROR) << "Error compiling shader: " << log; DLOG(ERROR) << "Shader compilation failure."; } #endif } } // namespace namespace gpu { ClearFramebufferResourceManager::ClearFramebufferResourceManager( const gles2::GLES2Decoder* decoder) : initialized_(false), program_(0u), buffer_id_(0u) { Initialize(decoder); } ClearFramebufferResourceManager::~ClearFramebufferResourceManager() { Destroy(); DCHECK(!buffer_id_); } void ClearFramebufferResourceManager::Initialize( const gles2::GLES2Decoder* decoder) { static_assert( kVertexPositionAttrib == 0u, "kVertexPositionAttrib must be 0"); DCHECK(!buffer_id_); glGenBuffersARB(1, &buffer_id_); glBindBuffer(GL_ARRAY_BUFFER, buffer_id_); const GLfloat kQuadVertices[] = {-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f}; glBufferData( GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW); decoder->RestoreBufferBindings(); initialized_ = true; } void ClearFramebufferResourceManager::Destroy() { if (!initialized_) return; glDeleteProgram(program_); glDeleteBuffersARB(1, &buffer_id_); buffer_id_ = 0; } void ClearFramebufferResourceManager::ClearFramebuffer( const gles2::GLES2Decoder* decoder, const gfx::Size& framebuffer_size, GLbitfield mask, GLfloat clear_color_red, GLfloat clear_color_green, GLfloat clear_color_blue, GLfloat clear_color_alpha, GLfloat clear_depth_value, GLint clear_stencil_value) { if (!initialized_) { DLOG(ERROR) << "Uninitialized manager."; return; } if (!program_) { program_ = glCreateProgram(); GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER); CompileShader(vertex_shader, g_vertex_shader_source); glAttachShader(program_, vertex_shader); GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); CompileShader(fragment_shader, g_fragment_shader_source); glAttachShader(program_, fragment_shader); glBindAttribLocation(program_, kVertexPositionAttrib, "a_position"); glLinkProgram(program_); #if DCHECK_IS_ON() GLint linked = GL_FALSE; glGetProgramiv(program_, GL_LINK_STATUS, &linked); if (GL_TRUE != linked) DLOG(ERROR) << "Program link failure."; #endif depth_handle_ = glGetUniformLocation(program_, "u_clear_depth"); color_handle_ = glGetUniformLocation(program_, "u_clear_color"); glDeleteShader(fragment_shader); glDeleteShader(vertex_shader); } glUseProgram(program_); #if DCHECK_IS_ON() glValidateProgram(program_); GLint validation_status = GL_FALSE; glGetProgramiv(program_, GL_VALIDATE_STATUS, &validation_status); if (GL_TRUE != validation_status) DLOG(ERROR) << "Invalid shader."; #endif decoder->ClearAllAttributes(); glEnableVertexAttribArray(kVertexPositionAttrib); glBindBuffer(GL_ARRAY_BUFFER, buffer_id_); glVertexAttribPointer(kVertexPositionAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0); glUniform1f(depth_handle_, clear_depth_value); glUniform4f(color_handle_, clear_color_red, clear_color_green, clear_color_blue, clear_color_alpha); if (!(mask & GL_COLOR_BUFFER_BIT)) { glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); } if (mask & GL_DEPTH_BUFFER_BIT) { glEnable(GL_DEPTH_TEST); glDepthFunc(GL_ALWAYS); } else { glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); } if (mask & GL_STENCIL_BUFFER_BIT) { glEnable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS, clear_stencil_value, 0xFF); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); } else { glDisable(GL_STENCIL_TEST); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glStencilMask(0); } glDisable(GL_CULL_FACE); glDisable(GL_BLEND); glDisable(GL_POLYGON_OFFSET_FILL); glViewport(0, 0, framebuffer_size.width(), framebuffer_size.height()); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); decoder->RestoreAllAttributes(); decoder->RestoreProgramBindings(); decoder->RestoreBufferBindings(); decoder->RestoreGlobalState(); } } // namespace gpu