Skip to content

Commit

Permalink
Work around NVidia's glLinkProgram bug
Browse files Browse the repository at this point in the history
glLinkProgram is supposed to start using a linked program
immediately if that program is the current program

BUG=110263


Review URL: https://chromiumcodereview.appspot.com/11227045

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@163642 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
gman@chromium.org committed Oct 23, 2012
1 parent 18b1ff8 commit c2a3caf
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 1 deletion.
7 changes: 6 additions & 1 deletion gpu/command_buffer/service/gles2_cmd_decoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4747,7 +4747,12 @@ void GLES2DecoderImpl::DoLinkProgram(GLuint program) {
fragment_translator,
feature_info_)) {
if (info == state_.current_program.get()) {
program_manager()->ClearUniforms(info);
if (!feature_info_->feature_flags().disable_workarounds) {
if (feature_info_->feature_flags().is_nvidia) {
glUseProgram(info->service_id());
}
program_manager()->ClearUniforms(info);
}
}
}
};
Expand Down
166 changes: 166 additions & 0 deletions gpu/command_buffer/tests/gl_program_unittests.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
// Copyright (c) 2012 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 <GLES2/gl2.h>
#include <GLES2/gl2ext.h>

#include "gpu/command_buffer/tests/gl_manager.h"
#include "gpu/command_buffer/tests/gl_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

#define SHADER(Src) #Src

namespace gpu {

class GLProgramTest : public testing::Test {
protected:
virtual void SetUp() {
gl_.Initialize(gfx::Size(4, 4));
}

virtual void TearDown() {
gl_.Destroy();
}

GLManager gl_;
};

TEST_F(GLProgramTest, GetSetUniform) {
static const char* v_shader_str = SHADER(
attribute vec4 a_vertex;
attribute vec3 a_normal;

uniform mat4 u_modelViewProjMatrix;

struct MyStruct
{
int x;
int y;
};

uniform MyStruct u_struct;
uniform float u_array[4];

varying vec3 v_normal;

void main()
{
v_normal = a_normal;
gl_Position = u_modelViewProjMatrix * a_vertex +
vec4(u_struct.x, u_struct.y, 0, 1) +
vec4(u_array[0], u_array[1], u_array[2], u_array[3]);
}
);
static const char* f_shader_str = SHADER(
varying mediump vec3 v_normal;

void main()
{
gl_FragColor = vec4(v_normal/2.0+vec3(0.5), 1);
}
);

// Load the program.
GLuint program = GLTestHelper::LoadProgram(v_shader_str, f_shader_str);
glUseProgram(program);
// Relink program.
glLinkProgram(program);

// These tests will fail on NVidia if not worked around by
// command buffer.
GLint location_sx = glGetUniformLocation(program, "u_struct.x");
GLint location_array_0 = glGetUniformLocation(program, "u_array[0]");

glUniform1i(location_sx, 3);
glUniform1f(location_array_0, 123);

GLint int_value = 0;
GLfloat float_value = 0;

glGetUniformiv(program, location_sx, &int_value);
EXPECT_EQ(3, int_value);
glGetUniformfv(program, location_array_0, &float_value);
EXPECT_EQ(123.0f, float_value);

GLTestHelper::CheckGLError("no errors", __LINE__);
}

TEST_F(GLProgramTest, NewShaderInCurrentProgram) {
static const char* v_shader_str = SHADER(
attribute vec4 a_position;
void main()
{
gl_Position = a_position;
}
);
static const char* f_red_shader_str = SHADER(
void main()
{
gl_FragColor = vec4(1, 0, 0, 1);
}
);
static const char* f_blue_shader_str = SHADER(
void main()
{
gl_FragColor = vec4(0, 0, 1, 1);
}
);

// Load the program.
GLuint vs = GLTestHelper::LoadShader(GL_VERTEX_SHADER, v_shader_str);
GLuint fs = GLTestHelper::LoadShader(GL_FRAGMENT_SHADER, f_red_shader_str);
GLuint program = GLTestHelper::SetupProgram(vs, fs);
glUseProgram(program);
glShaderSource(fs, 1, &f_blue_shader_str, NULL);
glCompileShader(fs);
glLinkProgram(program);
// We specifically don't call UseProgram again.
GLuint position_loc = glGetAttribLocation(program, "a_position");
GLTestHelper::SetupUnitQuad(position_loc);
glDrawArrays(GL_TRIANGLES, 0, 6);
uint8 expected_color[] = { 0, 0, 255, 255, };
EXPECT_TRUE(GLTestHelper::CheckPixels(0, 0, 1, 1, 0, expected_color));
GLTestHelper::CheckGLError("no errors", __LINE__);
}

TEST_F(GLProgramTest, UniformsInCurrentProgram) {
static const char* v_shader_str = SHADER(
attribute vec4 a_position;
void main()
{
gl_Position = a_position;
}
);
static const char* f_shader_str = SHADER(
precision mediump float;
uniform vec4 u_color;
void main()
{
gl_FragColor = u_color;;
}
);

// Load the program.
GLuint program = GLTestHelper::LoadProgram(v_shader_str, f_shader_str);
glUseProgram(program);

// Relink.
glLinkProgram(program);

// This test will fail on NVidia Linux if not worked around.
GLint color_location = glGetUniformLocation(program, "u_color");
glUniform4f(color_location, 0.0f, 0.0f, 1.0f, 1.0f);

// We specifically don't call UseProgram again.
GLuint position_loc = glGetAttribLocation(program, "a_position");
GLTestHelper::SetupUnitQuad(position_loc);
glDrawArrays(GL_TRIANGLES, 0, 6);
uint8 expected_color[] = { 0, 0, 255, 255, };
EXPECT_TRUE(GLTestHelper::CheckPixels(0, 0, 1, 1, 0, expected_color));
GLTestHelper::CheckGLError("no errors", __LINE__);
}

} // namespace gpu

1 change: 1 addition & 0 deletions gpu/gpu.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@
'command_buffer/tests/gl_manager.cc',
'command_buffer/tests/gl_manager.h',
'command_buffer/tests/gl_pointcoord_unittest.cc',
'command_buffer/tests/gl_program_unittests.cc',
'command_buffer/tests/gl_tests_main.cc',
'command_buffer/tests/gl_test_utils.cc',
'command_buffer/tests/gl_test_utils.h',
Expand Down

0 comments on commit c2a3caf

Please sign in to comment.