diff options
24 files changed, 678 insertions, 151 deletions
diff --git a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_color_buffer_float_rgb.txt b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_color_buffer_float_rgb.txt new file mode 100644 index 0000000..7f22008 --- /dev/null +++ b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_color_buffer_float_rgb.txt @@ -0,0 +1,64 @@ +Name + + CHROMIUM_color_buffer_float_rgb + +Name Strings + + GL_CHROMIUM_color_buffer_float_rgb + +Version + + Last Modifed Date: February 7, 2014 + +Dependencies + + This extension is written against the OpenGL ES 2.0 specification. + + OpenGL ES 2.0 is required. + + OES_texture_float is required. + +Overview + + This extension implements a subset of ARB_color_buffer_float on top of + OpenGL ES 2.0. + + This extension enables rendering to floating point RGB textures. When + this extension is enabled: + + * The 32-bit floating point type GL_RGB32F becomes available as a + color-renderable internal format. Textures created with type = FLOAT, + and internal format GL_RGB32F, can be attached to framebuffer object + color attachments for rendering. + + * GL_RGB / GL_RGB32F becomes an allowable format / internalformat parameter + pair for TexImage2D. The restriction in section 3.7.1 of the OpenGL ES + 2.0 spec that the internalformat parameter and format parameter of + TexImage2D must match is lifted for this case. + + Floating point RGB textures may still be created also with the unsized + GL_RGB internal format, but whether such textures are renderable is not + guaranteed. + +New Tokens + + Accepted by the <internalformat> parameter of TexImage2D: + + GL_RGB32F 0x8815 + +New Procedures and Functions + + None. + +Errors + + None. + +New State + + None. + +Revision History + + 2/7/2014 Documented the extension + diff --git a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_color_buffer_float_rgba.txt b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_color_buffer_float_rgba.txt new file mode 100644 index 0000000..d52bab851 --- /dev/null +++ b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_color_buffer_float_rgba.txt @@ -0,0 +1,64 @@ +Name + + CHROMIUM_color_buffer_float_rgba + +Name Strings + + GL_CHROMIUM_color_buffer_float_rgba + +Version + + Last Modifed Date: February 7, 2014 + +Dependencies + + This extension is written against the OpenGL ES 2.0 specification. + + OpenGL ES 2.0 is required. + + OES_texture_float is required. + +Overview + + This extension implements a subset of EXT_color_buffer_float on top of + OpenGL ES 2.0. + + This extension enables rendering to floating point RGBA textures. When + this extension is enabled: + + * The 32-bit floating point type GL_RGBA32F becomes available as a + color-renderable internal format. Textures created with type = FLOAT, + and internal format GL_RGBA32F, can be attached to framebuffer object + color attachments for rendering. + + * GL_RGBA / GL_RGBA32F becomes an allowable format / internalformat + parameter pair for TexImage2D. The restriction in section 3.7.1 of the + OpenGL ES 2.0 spec that the internalformat parameter and format parameter + of TexImage2D must match is lifted for this case. + + Floating point RGBA textures may still be created also with the unsized + GL_RGBA internal format, but whether such textures are renderable is not + guaranteed. + +New Tokens + + Accepted by the <internalformat> parameter of TexImage2D: + + GL_RGBA32F 0x8814 + +New Procedures and Functions + + None. + +Errors + + None. + +New State + + None. + +Revision History + + 2/7/2014 Documented the extension + diff --git a/gpu/GLES2/gl2extchromium.h b/gpu/GLES2/gl2extchromium.h index 11db4b7..50a6247 100644 --- a/gpu/GLES2/gl2extchromium.h +++ b/gpu/GLES2/gl2extchromium.h @@ -618,6 +618,20 @@ typedef GLuint (GL_APIENTRYP PFNGLINSERTSYNCPOINTCHROMIUMPROC) (); typedef void (GL_APIENTRYP PFNGLWAITSYNCPOINTCHROMIUMPROC) (GLuint sync_point); #endif /* GL_CHROMIUM_sync_point */ +#ifndef GL_CHROMIUM_color_buffer_float_rgba +#define GL_CHROMIUM_color_buffer_float_rgba 1 +#ifndef GL_RGBA32F +#define GL_RGBA32F 0x8814 +#endif +#endif /* GL_CHROMIUM_color_buffer_float_rgba */ + +#ifndef GL_CHROMIUM_color_buffer_float_rgb +#define GL_CHROMIUM_color_buffer_float_rgb 1 +#ifndef GL_RGB32F +#define GL_RGB32F 0x8815 +#endif +#endif /* GL_CHROMIUM_color_buffer_float_rgb */ + #ifdef __cplusplus } #endif diff --git a/gpu/command_buffer/service/context_group_unittest.cc b/gpu/command_buffer/service/context_group_unittest.cc index 3cce29c..23919bf 100644 --- a/gpu/command_buffer/service/context_group_unittest.cc +++ b/gpu/command_buffer/service/context_group_unittest.cc @@ -71,7 +71,7 @@ TEST_F(ContextGroupTest, Basic) { TEST_F(ContextGroupTest, InitializeNoExtensions) { TestHelper::SetupContextGroupInitExpectations(gl_.get(), - DisallowedFeatures(), ""); + DisallowedFeatures(), "", ""); group_->Initialize(decoder_.get(), DisallowedFeatures()); EXPECT_EQ(static_cast<uint32>(TestHelper::kNumVertexAttribs), group_->max_vertex_attribs()); @@ -106,7 +106,7 @@ TEST_F(ContextGroupTest, InitializeNoExtensions) { TEST_F(ContextGroupTest, MultipleContexts) { scoped_ptr<MockGLES2Decoder> decoder2_(new MockGLES2Decoder()); TestHelper::SetupContextGroupInitExpectations(gl_.get(), - DisallowedFeatures(), ""); + DisallowedFeatures(), "", ""); group_->Initialize(decoder_.get(), DisallowedFeatures()); group_->Initialize(decoder2_.get(), DisallowedFeatures()); diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc index 573cec4..e3ed72b 100644 --- a/gpu/command_buffer/service/feature_info.cc +++ b/gpu/command_buffer/service/feature_info.cc @@ -7,6 +7,7 @@ #include <set> #include "base/command_line.h" +#include "base/macros.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" @@ -99,7 +100,9 @@ void StringToWorkarounds( } // anonymous namespace. FeatureInfo::FeatureFlags::FeatureFlags() - : chromium_framebuffer_multisample(false), + : chromium_color_buffer_float_rgba(false), + chromium_color_buffer_float_rgb(false), + chromium_framebuffer_multisample(false), use_core_framebuffer_multisample(false), multisampled_render_to_texture(false), use_img_for_multisampled_render_to_texture(false), @@ -437,26 +440,28 @@ void FeatureInfo::InitializeFeatures() { bool enable_texture_half_float = false; bool enable_texture_half_float_linear = false; - bool have_arb_texture_float = extensions.Contains("GL_ARB_texture_float"); + bool may_enable_chromium_color_buffer_float = false; - if (have_arb_texture_float) { + if (extensions.Contains("GL_ARB_texture_float")) { enable_texture_float = true; enable_texture_float_linear = true; enable_texture_half_float = true; enable_texture_half_float_linear = true; + may_enable_chromium_color_buffer_float = true; } else { - if (extensions.Contains("GL_OES_texture_float") || have_arb_texture_float) { + if (extensions.Contains("GL_OES_texture_float")) { enable_texture_float = true; - if (extensions.Contains("GL_OES_texture_float_linear") || - have_arb_texture_float) { + if (extensions.Contains("GL_OES_texture_float_linear")) { enable_texture_float_linear = true; } + if ((is_es3 && extensions.Contains("GL_EXT_color_buffer_float")) || + feature_flags_.is_angle) { + may_enable_chromium_color_buffer_float = true; + } } - if (extensions.Contains("GL_OES_texture_half_float") || - have_arb_texture_float) { + if (extensions.Contains("GL_OES_texture_half_float")) { enable_texture_half_float = true; - if (extensions.Contains("GL_OES_texture_half_float_linear") || - have_arb_texture_float) { + if (extensions.Contains("GL_OES_texture_half_float_linear")) { enable_texture_half_float_linear = true; } } @@ -490,6 +495,62 @@ void FeatureInfo::InitializeFeatures() { } } + if (may_enable_chromium_color_buffer_float) { + COMPILE_ASSERT(GL_RGBA32F_ARB == GL_RGBA32F && + GL_RGBA32F_EXT == GL_RGBA32F && + GL_RGB32F_ARB == GL_RGB32F && + GL_RGB32F_EXT == GL_RGB32F, + sized_float_internal_format_variations_must_match); + // We don't check extension support beyond ARB_texture_float on desktop GL, + // and format support varies between GL configurations. For example, spec + // prior to OpenGL 3.0 mandates framebuffer support only for one + // implementation-chosen format, and ES3.0 EXT_color_buffer_float does not + // support rendering to RGB32F. Check for framebuffer completeness with + // formats that the extensions expose, and only enable an extension when a + // framebuffer created with its texture format is reported as complete. + GLint fb_binding = 0; + GLint tex_binding = 0; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fb_binding); + glGetIntegerv(GL_TEXTURE_BINDING_2D, &tex_binding); + + GLuint tex_id = 0; + GLuint fb_id = 0; + GLsizei width = 16; + + glGenTextures(1, &tex_id); + glGenFramebuffersEXT(1, &fb_id); + glBindTexture(GL_TEXTURE_2D, tex_id); + // Nearest filter needed for framebuffer completeness on some drivers. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, width, 0, GL_RGBA, + GL_FLOAT, NULL); + glBindFramebufferEXT(GL_FRAMEBUFFER, fb_id); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, tex_id, 0); + GLenum statusRGBA = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, width, width, 0, GL_RGB, + GL_FLOAT, NULL); + GLenum statusRGB = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER); + glDeleteFramebuffersEXT(1, &fb_id); + glDeleteTextures(1, &tex_id); + + glBindFramebufferEXT(GL_FRAMEBUFFER, static_cast<GLuint>(fb_binding)); + glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(tex_binding)); + + DCHECK(glGetError() == GL_NO_ERROR); + + if (statusRGBA == GL_FRAMEBUFFER_COMPLETE) { + validators_.texture_internal_format.AddValue(GL_RGBA32F); + feature_flags_.chromium_color_buffer_float_rgba = true; + AddExtensionString("GL_CHROMIUM_color_buffer_float_rgba"); + } + if (statusRGB == GL_FRAMEBUFFER_COMPLETE) { + validators_.texture_internal_format.AddValue(GL_RGB32F); + feature_flags_.chromium_color_buffer_float_rgb = true; + AddExtensionString("GL_CHROMIUM_color_buffer_float_rgb"); + } + } + // Check for multisample support if (!disallowed_features_.multisampling && !workarounds_.disable_framebuffer_multisample) { @@ -719,7 +780,14 @@ void FeatureInfo::InitializeFeatures() { } void FeatureInfo::AddExtensionString(const std::string& str) { - if (extensions_.find(str) == std::string::npos) { + size_t pos = extensions_.find(str); + while (pos != std::string::npos && + pos + str.length() < extensions_.length() && + extensions_.substr(pos + str.length(), 1) != " ") { + // This extension name is a substring of another. + pos = extensions_.find(str, pos + str.length()); + } + if (pos == std::string::npos) { extensions_ += (extensions_.empty() ? "" : " ") + str; } } diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h index 81a7f7c..a47a080 100644 --- a/gpu/command_buffer/service/feature_info.h +++ b/gpu/command_buffer/service/feature_info.h @@ -26,6 +26,8 @@ class GPU_EXPORT FeatureInfo : public base::RefCounted<FeatureInfo> { struct FeatureFlags { FeatureFlags(); + bool chromium_color_buffer_float_rgba; + bool chromium_color_buffer_float_rgb; bool chromium_framebuffer_multisample; // Use glBlitFramebuffer() and glRenderbufferStorageMultisample() with // GL_EXT_framebuffer_multisample-style semantics, since they are exposed diff --git a/gpu/command_buffer/service/feature_info_unittest.cc b/gpu/command_buffer/service/feature_info_unittest.cc index 53d1527..1a8cc12 100644 --- a/gpu/command_buffer/service/feature_info_unittest.cc +++ b/gpu/command_buffer/service/feature_info_unittest.cc @@ -280,6 +280,10 @@ TEST_F(FeatureInfoTest, InitializeNoExtensions) { GL_DEPTH24_STENCIL8)); EXPECT_FALSE(info_->validators()->texture_internal_format.IsValid( GL_DEPTH_STENCIL)); + EXPECT_FALSE(info_->validators()->texture_internal_format.IsValid( + GL_RGBA32F)); + EXPECT_FALSE(info_->validators()->texture_internal_format.IsValid( + GL_RGB32F)); EXPECT_FALSE(info_->validators()->texture_format.IsValid( GL_DEPTH_STENCIL)); EXPECT_FALSE(info_->validators()->pixel_type.IsValid( @@ -407,6 +411,19 @@ TEST_F(FeatureInfoTest, InitializeEXT_read_format_bgra) { GL_BGRA8_EXT)); } +TEST_F(FeatureInfoTest, InitializeARB_texture_float) { + SetupInitExpectations("GL_ARB_texture_float"); + EXPECT_TRUE(info_->feature_flags().chromium_color_buffer_float_rgba); + EXPECT_TRUE(info_->feature_flags().chromium_color_buffer_float_rgb); + std::string extensions = info_->extensions() + " "; + EXPECT_THAT(extensions, HasSubstr("GL_CHROMIUM_color_buffer_float_rgb ")); + EXPECT_THAT(extensions, HasSubstr("GL_CHROMIUM_color_buffer_float_rgba")); + EXPECT_TRUE(info_->validators()->texture_internal_format.IsValid( + GL_RGBA32F)); + EXPECT_TRUE(info_->validators()->texture_internal_format.IsValid( + GL_RGB32F)); +} + TEST_F(FeatureInfoTest, InitializeOES_texture_floatGLES2) { SetupInitExpectations("GL_OES_texture_float"); EXPECT_FALSE(info_->feature_flags().enable_texture_float_linear); diff --git a/gpu/command_buffer/service/framebuffer_manager_unittest.cc b/gpu/command_buffer/service/framebuffer_manager_unittest.cc index a9b4388..ba123dd 100644 --- a/gpu/command_buffer/service/framebuffer_manager_unittest.cc +++ b/gpu/command_buffer/service/framebuffer_manager_unittest.cc @@ -33,7 +33,6 @@ class FramebufferManagerTest : public testing::Test { NULL, new FeatureInfo(), kMaxTextureSize, kMaxCubemapSize), renderbuffer_manager_(NULL, kMaxRenderbufferSize, kMaxSamples, kDepth24Supported) { - } virtual ~FramebufferManagerTest() { manager_.Destroy(false); @@ -110,21 +109,29 @@ class FramebufferInfoTest : public testing::Test { FramebufferInfoTest() : manager_(1, 1), - texture_manager_( - NULL, new FeatureInfo(), kMaxTextureSize, kMaxCubemapSize), + feature_info_(new FeatureInfo()), renderbuffer_manager_(NULL, kMaxRenderbufferSize, kMaxSamples, kDepth24Supported) { + texture_manager_.reset(new TextureManager(NULL, feature_info_.get(), + kMaxTextureSize, kMaxCubemapSize)); } virtual ~FramebufferInfoTest() { manager_.Destroy(false); - texture_manager_.Destroy(false); + texture_manager_->Destroy(false); renderbuffer_manager_.Destroy(false); } protected: virtual void SetUp() { + InitializeContext("", ""); + } + + void InitializeContext(const char* gl_version, const char* extensions) { gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>()); ::gfx::MockGLInterface::SetGLInterface(gl_.get()); + TestHelper::SetupFeatureInfoInitExpectationsWithGLVersion(gl_.get(), + extensions, "", gl_version); + feature_info_->Initialize(); manager_.CreateFramebuffer(kClient1Id, kService1Id); error_state_.reset(new ::testing::StrictMock<gles2::MockErrorState>()); framebuffer_ = manager_.GetFramebuffer(kClient1Id); @@ -140,7 +147,8 @@ class FramebufferInfoTest : public testing::Test { scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_; FramebufferManager manager_; Framebuffer* framebuffer_; - TextureManager texture_manager_; + scoped_refptr<FeatureInfo> feature_info_; + scoped_ptr<TextureManager> texture_manager_; RenderbufferManager renderbuffer_manager_; scoped_ptr<MockErrorState> error_state_; }; @@ -268,7 +276,7 @@ TEST_F(FramebufferInfoTest, AttachRenderbuffer) { // check marking them as cleared. manager_.MarkAttachmentsAsCleared( - framebuffer_, &renderbuffer_manager_, &texture_manager_); + framebuffer_, &renderbuffer_manager_, texture_manager_.get()); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT)); EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE), @@ -319,7 +327,7 @@ TEST_F(FramebufferInfoTest, AttachRenderbuffer) { // Clear it. manager_.MarkAttachmentsAsCleared( - framebuffer_, &renderbuffer_manager_, &texture_manager_); + framebuffer_, &renderbuffer_manager_, texture_manager_.get()); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_TRUE(framebuffer_->IsCleared()); @@ -419,9 +427,9 @@ TEST_F(FramebufferInfoTest, AttachTexture) { EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT), framebuffer_->IsPossiblyComplete()); - texture_manager_.CreateTexture(kTextureClient1Id, kTextureService1Id); + texture_manager_->CreateTexture(kTextureClient1Id, kTextureService1Id); scoped_refptr<TextureRef> texture1( - texture_manager_.GetTexture(kTextureClient1Id)); + texture_manager_->GetTexture(kTextureClient1Id)); ASSERT_TRUE(texture1.get() != NULL); // check adding one attachment @@ -434,8 +442,8 @@ TEST_F(FramebufferInfoTest, AttachTexture) { EXPECT_EQ(static_cast<GLenum>(0), framebuffer_->GetColorAttachmentFormat()); // Try format that doesn't work with COLOR_ATTACHMENT0 - texture_manager_.SetTarget(texture1.get(), GL_TEXTURE_2D); - texture_manager_.SetLevelInfo(texture1.get(), + texture_manager_->SetTarget(texture1.get(), GL_TEXTURE_2D); + texture_manager_->SetLevelInfo(texture1.get(), GL_TEXTURE_2D, kLevel1, kBadFormat1, @@ -450,7 +458,7 @@ TEST_F(FramebufferInfoTest, AttachTexture) { framebuffer_->IsPossiblyComplete()); // Try a good format. - texture_manager_.SetLevelInfo(texture1.get(), + texture_manager_->SetLevelInfo(texture1.get(), GL_TEXTURE_2D, kLevel1, kFormat1, @@ -464,7 +472,7 @@ TEST_F(FramebufferInfoTest, AttachTexture) { EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE), framebuffer_->IsPossiblyComplete()); EXPECT_FALSE(framebuffer_->IsCleared()); - texture_manager_.SetLevelInfo(texture1.get(), + texture_manager_->SetLevelInfo(texture1.get(), GL_TEXTURE_2D, kLevel1, kFormat1, @@ -491,12 +499,12 @@ TEST_F(FramebufferInfoTest, AttachTexture) { EXPECT_TRUE(attachment->cleared()); // Check replacing an attachment - texture_manager_.CreateTexture(kTextureClient2Id, kTextureService2Id); + texture_manager_->CreateTexture(kTextureClient2Id, kTextureService2Id); scoped_refptr<TextureRef> texture2( - texture_manager_.GetTexture(kTextureClient2Id)); + texture_manager_->GetTexture(kTextureClient2Id)); ASSERT_TRUE(texture2.get() != NULL); - texture_manager_.SetTarget(texture2.get(), GL_TEXTURE_2D); - texture_manager_.SetLevelInfo(texture2.get(), + texture_manager_->SetTarget(texture2.get(), GL_TEXTURE_2D); + texture_manager_->SetLevelInfo(texture2.get(), GL_TEXTURE_2D, kLevel2, kFormat2, @@ -525,7 +533,7 @@ TEST_F(FramebufferInfoTest, AttachTexture) { EXPECT_TRUE(attachment->cleared()); // Check changing attachment - texture_manager_.SetLevelInfo(texture2.get(), + texture_manager_->SetLevelInfo(texture2.get(), GL_TEXTURE_2D, kLevel3, kFormat3, @@ -550,7 +558,7 @@ TEST_F(FramebufferInfoTest, AttachTexture) { EXPECT_FALSE(framebuffer_->IsCleared()); // Set to size 0 - texture_manager_.SetLevelInfo(texture2.get(), + texture_manager_->SetLevelInfo(texture2.get(), GL_TEXTURE_2D, kLevel3, kFormat3, @@ -574,6 +582,65 @@ TEST_F(FramebufferInfoTest, AttachTexture) { EXPECT_TRUE(framebuffer_->IsCleared()); } +class FramebufferInfoFloatTest : public FramebufferInfoTest { + public: + FramebufferInfoFloatTest() + : FramebufferInfoTest() { + } + virtual ~FramebufferInfoFloatTest() { + } + + protected: + virtual void SetUp() { + InitializeContext("OpenGL ES 3.0", + "GL_OES_texture_float GL_EXT_color_buffer_float"); + } +}; + +TEST_F(FramebufferInfoFloatTest, AttachFloatTexture) { + const GLuint kTextureClientId = 33; + const GLuint kTextureServiceId = 333; + const GLint kDepth = 1; + const GLint kBorder = 0; + const GLenum kType = GL_FLOAT; + const GLsizei kWidth = 16; + const GLsizei kHeight = 32; + const GLint kLevel = 0; + const GLenum kFormat = GL_RGBA; + const GLenum kInternalFormat = GL_RGBA32F; + const GLenum kTarget = GL_TEXTURE_2D; + const GLsizei kSamples = 0; + EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); + EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT)); + EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT)); + + texture_manager_->CreateTexture(kTextureClientId, kTextureServiceId); + scoped_refptr<TextureRef> texture( + texture_manager_->GetTexture(kTextureClientId)); + ASSERT_TRUE(texture.get() != NULL); + + framebuffer_->AttachTexture( + GL_COLOR_ATTACHMENT0, texture.get(), kTarget, kLevel, kSamples); + EXPECT_EQ(static_cast<GLenum>(0), framebuffer_->GetColorAttachmentFormat()); + + texture_manager_->SetTarget(texture.get(), GL_TEXTURE_2D); + texture_manager_->SetLevelInfo(texture.get(), + GL_TEXTURE_2D, + kLevel, + kInternalFormat, + kWidth, + kHeight, + kDepth, + kBorder, + kFormat, + kType, + false); + // Texture with a sized float internalformat is allowed as an attachment + // since float color attachment extension is present. + EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE), + framebuffer_->IsPossiblyComplete()); +} + TEST_F(FramebufferInfoTest, UnbindRenderbuffer) { const GLuint kRenderbufferClient1Id = 33; const GLuint kRenderbufferService1Id = 333; @@ -618,13 +685,13 @@ TEST_F(FramebufferInfoTest, UnbindTexture) { const GLint kLevel1 = 0; const GLint kSamples1 = 0; - texture_manager_.CreateTexture(kTextureClient1Id, kTextureService1Id); + texture_manager_->CreateTexture(kTextureClient1Id, kTextureService1Id); scoped_refptr<TextureRef> texture1( - texture_manager_.GetTexture(kTextureClient1Id)); + texture_manager_->GetTexture(kTextureClient1Id)); ASSERT_TRUE(texture1.get() != NULL); - texture_manager_.CreateTexture(kTextureClient2Id, kTextureService2Id); + texture_manager_->CreateTexture(kTextureClient2Id, kTextureService2Id); scoped_refptr<TextureRef> texture2( - texture_manager_.GetTexture(kTextureClient2Id)); + texture_manager_->GetTexture(kTextureClient2Id)); ASSERT_TRUE(texture2.get() != NULL); // Attach to 2 attachment points. @@ -661,9 +728,9 @@ TEST_F(FramebufferInfoTest, IsCompleteMarkAsComplete) { Renderbuffer* renderbuffer1 = renderbuffer_manager_.GetRenderbuffer(kRenderbufferClient1Id); ASSERT_TRUE(renderbuffer1 != NULL); - texture_manager_.CreateTexture(kTextureClient2Id, kTextureService2Id); + texture_manager_->CreateTexture(kTextureClient2Id, kTextureService2Id); scoped_refptr<TextureRef> texture2( - texture_manager_.GetTexture(kTextureClient2Id)); + texture_manager_->GetTexture(kTextureClient2Id)); ASSERT_TRUE(texture2.get() != NULL); // Check MarkAsComlete marks as complete. @@ -681,7 +748,7 @@ TEST_F(FramebufferInfoTest, IsCompleteMarkAsComplete) { // Check MarkAttachmentsAsCleared marks as complete. manager_.MarkAttachmentsAsCleared( - framebuffer_, &renderbuffer_manager_, &texture_manager_); + framebuffer_, &renderbuffer_manager_, texture_manager_.get()); EXPECT_TRUE(manager_.IsComplete(framebuffer_)); // Check Unbind marks as not complete. @@ -707,16 +774,16 @@ TEST_F(FramebufferInfoTest, GetStatus) { Renderbuffer* renderbuffer1 = renderbuffer_manager_.GetRenderbuffer(kRenderbufferClient1Id); ASSERT_TRUE(renderbuffer1 != NULL); - texture_manager_.CreateTexture(kTextureClient2Id, kTextureService2Id); + texture_manager_->CreateTexture(kTextureClient2Id, kTextureService2Id); scoped_refptr<TextureRef> texture2( - texture_manager_.GetTexture(kTextureClient2Id)); + texture_manager_->GetTexture(kTextureClient2Id)); ASSERT_TRUE(texture2.get() != NULL); - texture_manager_.SetTarget(texture2.get(), GL_TEXTURE_2D); + texture_manager_->SetTarget(texture2.get(), GL_TEXTURE_2D); EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER)) .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) .RetiresOnSaturation(); - framebuffer_->GetStatus(&texture_manager_, GL_FRAMEBUFFER); + framebuffer_->GetStatus(texture_manager_.get(), GL_FRAMEBUFFER); // Check a second call for the same type does not call anything if (!framebuffer_->AllowFramebufferComboCompleteMapForTesting()) { @@ -724,14 +791,14 @@ TEST_F(FramebufferInfoTest, GetStatus) { .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) .RetiresOnSaturation(); } - framebuffer_->GetStatus(&texture_manager_, GL_FRAMEBUFFER); + framebuffer_->GetStatus(texture_manager_.get(), GL_FRAMEBUFFER); // Check changing the attachments calls CheckFramebufferStatus. framebuffer_->AttachTexture( GL_COLOR_ATTACHMENT0, texture2.get(), kTarget1, kLevel1, kSamples1); EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER)) .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)).RetiresOnSaturation(); - framebuffer_->GetStatus(&texture_manager_, GL_FRAMEBUFFER); + framebuffer_->GetStatus(texture_manager_.get(), GL_FRAMEBUFFER); // Check a second call for the same type does not call anything. if (!framebuffer_->AllowFramebufferComboCompleteMapForTesting()) { @@ -739,13 +806,13 @@ TEST_F(FramebufferInfoTest, GetStatus) { .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) .RetiresOnSaturation(); } - framebuffer_->GetStatus(&texture_manager_, GL_FRAMEBUFFER); + framebuffer_->GetStatus(texture_manager_.get(), GL_FRAMEBUFFER); // Check a second call with a different target calls CheckFramebufferStatus. EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER)) .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) .RetiresOnSaturation(); - framebuffer_->GetStatus(&texture_manager_, GL_READ_FRAMEBUFFER); + framebuffer_->GetStatus(texture_manager_.get(), GL_READ_FRAMEBUFFER); // Check a second call for the same type does not call anything. if (!framebuffer_->AllowFramebufferComboCompleteMapForTesting()) { @@ -753,14 +820,14 @@ TEST_F(FramebufferInfoTest, GetStatus) { .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) .RetiresOnSaturation(); } - framebuffer_->GetStatus(&texture_manager_, GL_READ_FRAMEBUFFER); + framebuffer_->GetStatus(texture_manager_.get(), GL_READ_FRAMEBUFFER); // Check adding another attachment calls CheckFramebufferStatus. framebuffer_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, renderbuffer1); EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER)) .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) .RetiresOnSaturation(); - framebuffer_->GetStatus(&texture_manager_, GL_READ_FRAMEBUFFER); + framebuffer_->GetStatus(texture_manager_.get(), GL_READ_FRAMEBUFFER); // Check a second call for the same type does not call anything. if (!framebuffer_->AllowFramebufferComboCompleteMapForTesting()) { @@ -768,12 +835,12 @@ TEST_F(FramebufferInfoTest, GetStatus) { .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) .RetiresOnSaturation(); } - framebuffer_->GetStatus(&texture_manager_, GL_READ_FRAMEBUFFER); + framebuffer_->GetStatus(texture_manager_.get(), GL_READ_FRAMEBUFFER); // Check changing the format calls CheckFramebuffferStatus. TestHelper::SetTexParameterWithExpectations(gl_.get(), error_state_.get(), - &texture_manager_, + texture_manager_.get(), texture2.get(), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE, @@ -783,11 +850,11 @@ TEST_F(FramebufferInfoTest, GetStatus) { .WillOnce(Return(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT)) .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) .RetiresOnSaturation(); - framebuffer_->GetStatus(&texture_manager_, GL_READ_FRAMEBUFFER); + framebuffer_->GetStatus(texture_manager_.get(), GL_READ_FRAMEBUFFER); // Check since it did not return FRAMEBUFFER_COMPLETE that it calls // CheckFramebufferStatus - framebuffer_->GetStatus(&texture_manager_, GL_READ_FRAMEBUFFER); + framebuffer_->GetStatus(texture_manager_.get(), GL_READ_FRAMEBUFFER); // Check putting it back does not call CheckFramebufferStatus. if (!framebuffer_->AllowFramebufferComboCompleteMapForTesting()) { @@ -797,12 +864,12 @@ TEST_F(FramebufferInfoTest, GetStatus) { } TestHelper::SetTexParameterWithExpectations(gl_.get(), error_state_.get(), - &texture_manager_, + texture_manager_.get(), texture2.get(), GL_TEXTURE_WRAP_S, GL_REPEAT, GL_NO_ERROR); - framebuffer_->GetStatus(&texture_manager_, GL_READ_FRAMEBUFFER); + framebuffer_->GetStatus(texture_manager_.get(), GL_READ_FRAMEBUFFER); // Check Unbinding does not call CheckFramebufferStatus framebuffer_->UnbindRenderbuffer(GL_RENDERBUFFER, renderbuffer1); @@ -811,7 +878,7 @@ TEST_F(FramebufferInfoTest, GetStatus) { .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) .RetiresOnSaturation(); } - framebuffer_->GetStatus(&texture_manager_, GL_READ_FRAMEBUFFER); + framebuffer_->GetStatus(texture_manager_.get(), GL_READ_FRAMEBUFFER); } } // namespace gles2 diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 99b9976..414ecc6 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -8159,7 +8159,7 @@ void GLES2DecoderImpl::DoCompressedTexSubImage2D( return; } if (!texture->ValidForTexture( - target, level, xoffset, yoffset, width, height, format, type)) { + target, level, xoffset, yoffset, width, height, type)) { LOCAL_SET_GL_ERROR( GL_INVALID_VALUE, "glCompressedTexSubImage2D", "bad dimensions."); return; @@ -8228,9 +8228,9 @@ void GLES2DecoderImpl::DoCopyTexImage2D( GL_INVALID_VALUE, "glCopyTexImage2D", "dimensions out of range"); return; } - if (!texture_manager()->ValidateTextureParameters( - state_.GetErrorState(), "glCopyTexImage2D", target, internal_format, - GL_UNSIGNED_BYTE, level)) { + if (!texture_manager()->ValidateFormatAndTypeCombination( + state_.GetErrorState(), "glCopyTexImage2D", internal_format, + GL_UNSIGNED_BYTE)) { return; } @@ -8343,7 +8343,7 @@ void GLES2DecoderImpl::DoCopyTexSubImage2D( GLenum format = 0; if (!texture->GetLevelType(target, level, &type, &format) || !texture->ValidForTexture( - target, level, xoffset, yoffset, width, height, format, type)) { + target, level, xoffset, yoffset, width, height, type)) { LOCAL_SET_GL_ERROR( GL_INVALID_VALUE, "glCopyTexSubImage2D", "bad dimensions."); return; @@ -8449,14 +8449,6 @@ bool GLES2DecoderImpl::ValidateTexSubImage2D( LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "height < 0"); return false; } - if (!validators_->texture_format.IsValid(format)) { - LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, format, "format"); - return false; - } - if (!validators_->pixel_type.IsValid(type)) { - LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, type, "type"); - return false; - } TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget( &state_, target); if (!texture_ref) { @@ -8473,10 +8465,8 @@ bool GLES2DecoderImpl::ValidateTexSubImage2D( GL_INVALID_OPERATION, function_name, "level does not exist."); return false; } - if (format != internal_format) { - LOCAL_SET_GL_ERROR( - GL_INVALID_OPERATION, - function_name, "format does not match internal format."); + if (!texture_manager()->ValidateTextureParameters(state_.GetErrorState(), + function_name, format, type, internal_format, level)) { return false; } if (type != current_type) { @@ -8492,7 +8482,7 @@ bool GLES2DecoderImpl::ValidateTexSubImage2D( return false; } if (!texture->ValidForTexture( - target, level, xoffset, yoffset, width, height, format, type)) { + target, level, xoffset, yoffset, width, height, type)) { LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "bad dimensions."); return false; } diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc index 2756257..4d1c77e 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc @@ -8903,6 +8903,78 @@ TEST_F(GLES2DecoderManualInitTest, ClearUniformsBeforeFirstProgramUse) { } } +TEST_F(GLES2DecoderManualInitTest, TexImage2DFloatOnGLES2) { + InitDecoder("GL_OES_texture_float", // extensions + "opengl es 2.0", // gl version + false, // has alpha + false, // has depth + false, // has stencil + false, // request alpha + false, // request depth + false, // request stencil + false); // bind generates resource + DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); + DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 17, 0, GL_RGBA, GL_FLOAT, 0, 0); + DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 16, 17, 0, GL_RGB, GL_FLOAT, 0, 0); + DoTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 16, 17, 0, GL_LUMINANCE, + GL_FLOAT, 0, 0); + DoTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 16, 17, 0, GL_ALPHA, GL_FLOAT, + 0, 0); + DoTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, 16, 17, 0, + GL_LUMINANCE_ALPHA, GL_FLOAT, 0, 0); +} + +TEST_F(GLES2DecoderManualInitTest, TexImage2DFloatOnGLES3) { + InitDecoder("GL_OES_texture_float GL_EXT_color_buffer_float", // extensions + "opengl es 3.0", // gl version + false, // has alpha + false, // has depth + false, // has stencil + false, // request alpha + false, // request depth + false, // request stencil + false); // bind generates resource + DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); + DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 17, 0, GL_RGBA, GL_FLOAT, 0, 0); + DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 16, 17, 0, GL_RGB, GL_FLOAT, 0, 0); + DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 16, 17, 0, GL_RGBA, GL_FLOAT, 0, + 0); + DoTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 16, 17, 0, GL_LUMINANCE, + GL_FLOAT, 0, 0); + DoTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 16, 17, 0, GL_ALPHA, GL_FLOAT, + 0, 0); + DoTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, 16, 17, 0, + GL_LUMINANCE_ALPHA, GL_FLOAT, 0, 0); +} + +TEST_F(GLES2DecoderManualInitTest, TexImage2DFloatConvertsFormatDesktop) { + InitDecoder("GL_ARB_texture_float", // extensions + "2.1", // gl version + false, // has alpha + false, // has depth + false, // has stencil + false, // request alpha + false, // request depth + false, // request stencil + false); // bind generates resource + DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); + DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 16, 17, 0, GL_RGBA, GL_FLOAT, 0, + 0); + DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, 16, 17, 0, GL_RGB, GL_FLOAT, 0, 0); + DoTexImage2DConvertInternalFormat(GL_TEXTURE_2D, 0, GL_RGBA, 16, 17, 0, + GL_RGBA, GL_FLOAT, 0, 0, GL_RGBA32F_ARB); + DoTexImage2DConvertInternalFormat(GL_TEXTURE_2D, 0, GL_RGB, 16, 17, 0, + GL_RGB, GL_FLOAT, 0, 0, GL_RGB32F_ARB); + DoTexImage2DConvertInternalFormat(GL_TEXTURE_2D, 0, GL_LUMINANCE, 16, 17, 0, + GL_LUMINANCE, GL_FLOAT, 0, 0, + GL_LUMINANCE32F_ARB); + DoTexImage2DConvertInternalFormat(GL_TEXTURE_2D, 0, GL_ALPHA, 16, 17, 0, + GL_ALPHA, GL_FLOAT, 0, 0, GL_ALPHA32F_ARB); + DoTexImage2DConvertInternalFormat(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, 16, + 17, 0, GL_LUMINANCE_ALPHA, GL_FLOAT, 0, 0, + GL_LUMINANCE_ALPHA32F_ARB); +} + // TODO(gman): Complete this test. // TEST_F(GLES2DecoderTest, CompressedTexImage2DGLError) { // } diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc index 6f74bde..0b35b39 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc @@ -141,8 +141,21 @@ void GLES2DecoderTestBase::InitDecoderWithCommandLine( InSequence sequence; + surface_ = new gfx::GLSurfaceStub; + surface_->SetSize(gfx::Size(kBackBufferWidth, kBackBufferHeight)); + + // Context needs to be created before initializing ContextGroup, which will + // in turn initialize FeatureInfo, which needs a context to determine + // extension support. + context_ = new gfx::GLContextStubWithExtensions; + context_->AddExtensionsString(extensions); + context_->SetGLVersionString(gl_version); + + context_->MakeCurrent(surface_.get()); + gfx::GLSurface::InitializeDynamicMockBindingsForTests(context_); + TestHelper::SetupContextGroupInitExpectations(gl_.get(), - DisallowedFeatures(), extensions); + DisallowedFeatures(), extensions, gl_version); // We initialize the ContextGroup with a MockGLES2Decoder so that // we can use the ContextGroup to figure out how the real GLES2Decoder @@ -281,16 +294,6 @@ void GLES2DecoderTestBase::InitDecoderWithCommandLine( shared_memory_id_ = kSharedMemoryId; shared_memory_base_ = buffer.ptr; - surface_ = new gfx::GLSurfaceStub; - surface_->SetSize(gfx::Size(kBackBufferWidth, kBackBufferHeight)); - - context_ = new gfx::GLContextStubWithExtensions; - context_->AddExtensionsString(extensions); - context_->SetGLVersionString(gl_version); - - context_->MakeCurrent(surface_.get()); - gfx::GLSurface::InitializeDynamicMockBindingsForTests(context_); - int32 attributes[] = { EGL_ALPHA_SIZE, request_alpha ? 8 : 0, EGL_DEPTH_SIZE, request_depth ? 24 : 0, @@ -834,6 +837,28 @@ void GLES2DecoderTestBase::DoTexImage2D( EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); } +void GLES2DecoderTestBase::DoTexImage2DConvertInternalFormat( + GLenum target, GLint level, GLenum requested_internal_format, + GLsizei width, GLsizei height, GLint border, + GLenum format, GLenum type, + uint32 shared_memory_id, uint32 shared_memory_offset, + GLenum expected_internal_format) { + EXPECT_CALL(*gl_, GetError()) + .WillOnce(Return(GL_NO_ERROR)) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, TexImage2D(target, level, expected_internal_format, + width, height, border, format, type, _)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, GetError()) + .WillOnce(Return(GL_NO_ERROR)) + .RetiresOnSaturation(); + cmds::TexImage2D cmd; + cmd.Init(target, level, requested_internal_format, width, height, border, + format, type, shared_memory_id, shared_memory_offset); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); +} + void GLES2DecoderTestBase::DoCompressedTexImage2D( GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLint border, diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h index 733724f..62ca07c 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h @@ -244,6 +244,12 @@ class GLES2DecoderTestBase : public testing::Test { GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, uint32 shared_memory_id, uint32 shared_memory_offset); + void DoTexImage2DConvertInternalFormat( + GLenum target, GLint level, GLenum requested_internal_format, + GLsizei width, GLsizei height, GLint border, + GLenum format, GLenum type, + uint32 shared_memory_id, uint32 shared_memory_offset, + GLenum expected_internal_format); void DoRenderbufferStorage( GLenum target, GLenum internal_format, GLenum actual_format, GLsizei width, GLsizei height, GLenum error); diff --git a/gpu/command_buffer/service/test_helper.cc b/gpu/command_buffer/service/test_helper.cc index 92c5ec4..c164eea 100644 --- a/gpu/command_buffer/service/test_helper.cc +++ b/gpu/command_buffer/service/test_helper.cc @@ -227,16 +227,20 @@ void TestHelper::SetupTextureManagerDestructionExpectations( void TestHelper::SetupContextGroupInitExpectations( ::gfx::MockGLInterface* gl, const DisallowedFeatures& disallowed_features, - const char* extensions) { + const char* extensions, + const char* gl_version) { InSequence sequence; - SetupFeatureInfoInitExpectations(gl, extensions); + SetupFeatureInfoInitExpectationsWithGLVersion(gl, extensions, "", gl_version); + + std::string l_version(StringToLowerASCII(std::string(gl_version))); + bool is_es3 = (l_version.substr(0, 12) == "opengl es 3."); EXPECT_CALL(*gl, GetIntegerv(GL_MAX_RENDERBUFFER_SIZE, _)) .WillOnce(SetArgumentPointee<1>(kMaxRenderbufferSize)) .RetiresOnSaturation(); if (strstr(extensions, "GL_EXT_framebuffer_multisample") || - strstr(extensions, "GL_EXT_multisampled_render_to_texture")) { + strstr(extensions, "GL_EXT_multisampled_render_to_texture") || is_es3) { EXPECT_CALL(*gl, GetIntegerv(GL_MAX_SAMPLES, _)) .WillOnce(SetArgumentPointee<1>(kMaxSamples)) .RetiresOnSaturation(); @@ -297,6 +301,78 @@ void TestHelper::SetupFeatureInfoInitExpectationsWithGLVersion( EXPECT_CALL(*gl, GetString(GL_VERSION)) .WillOnce(Return(reinterpret_cast<const uint8*>(gl_version))) .RetiresOnSaturation(); + + std::string l_version(StringToLowerASCII(std::string(gl_version))); + bool is_es3 = (l_version.substr(0, 12) == "opengl es 3."); + + if (strstr(extensions, "GL_ARB_texture_float") || + (is_es3 && strstr(extensions, "GL_EXT_color_buffer_float"))) { + static const GLuint gl_ids[] = {101, 102}; + const GLsizei width = 16; + EXPECT_CALL(*gl, GetIntegerv(GL_FRAMEBUFFER_BINDING, _)) + .WillOnce(SetArgumentPointee<1>(gl_ids[0])) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, GetIntegerv(GL_TEXTURE_BINDING_2D, _)) + .WillOnce(SetArgumentPointee<1>(gl_ids[0])) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, GenTextures(1, _)) + .WillOnce(SetArrayArgument<1>(gl_ids + 1, gl_ids + 2)) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, GenFramebuffersEXT(1, _)) + .WillOnce(SetArrayArgument<1>(gl_ids + 1, gl_ids + 2)) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, BindTexture(GL_TEXTURE_2D, gl_ids[1])) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + GL_NEAREST)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, width, 0, + GL_RGBA, GL_FLOAT, _)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, BindFramebufferEXT(GL_FRAMEBUFFER, gl_ids[1])) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, FramebufferTexture2DEXT(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl_ids[1], 0)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, CheckFramebufferStatusEXT(GL_FRAMEBUFFER)) + .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, TexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, width, width, 0, + GL_RGB, GL_FLOAT, _)) + .Times(1) + .RetiresOnSaturation(); + if (is_es3) { + EXPECT_CALL(*gl, CheckFramebufferStatusEXT(GL_FRAMEBUFFER)) + .WillOnce(Return(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT)) + .RetiresOnSaturation(); + } else { + EXPECT_CALL(*gl, CheckFramebufferStatusEXT(GL_FRAMEBUFFER)) + .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) + .RetiresOnSaturation(); + } + EXPECT_CALL(*gl, DeleteFramebuffersEXT(1, _)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, DeleteTextures(1, _)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, BindFramebufferEXT(GL_FRAMEBUFFER, gl_ids[0])) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, BindTexture(GL_TEXTURE_2D, gl_ids[0])) + .Times(1) + .RetiresOnSaturation(); + if (DCHECK_IS_ON()) { + EXPECT_CALL(*gl, GetError()) + .WillOnce(Return(GL_NO_ERROR)) + .RetiresOnSaturation(); + } + } } void TestHelper::SetupExpectationsForClearingUniforms( diff --git a/gpu/command_buffer/service/test_helper.h b/gpu/command_buffer/service/test_helper.h index a619073..99041e7 100644 --- a/gpu/command_buffer/service/test_helper.h +++ b/gpu/command_buffer/service/test_helper.h @@ -65,7 +65,8 @@ class TestHelper { static void SetupContextGroupInitExpectations( ::gfx::MockGLInterface* gl, const DisallowedFeatures& disallowed_features, - const char* extensions); + const char* extensions, + const char* gl_version); static void SetupFeatureInfoInitExpectations( ::gfx::MockGLInterface* gl, const char* extensions); static void SetupFeatureInfoInitExpectationsWithGLVersion( diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc index 72d3b4c..a0a60c1 100644 --- a/gpu/command_buffer/service/texture_manager.cc +++ b/gpu/command_buffer/service/texture_manager.cc @@ -517,7 +517,6 @@ bool Texture::ValidForTexture( GLint yoffset, GLsizei width, GLsizei height, - GLenum format, GLenum type) const { size_t face_index = GLTargetToFaceIndex(target); if (level >= 0 && face_index < level_infos_.size() && @@ -531,7 +530,6 @@ bool Texture::ValidForTexture( yoffset >= 0 && right <= info.width && top <= info.height && - format == info.internal_format && type == info.type; } return false; @@ -1259,20 +1257,10 @@ void TextureManager::IncFramebufferStateChangeCount() { framebuffer_manager_->IncFramebufferStateChangeCount(); } -bool TextureManager::ValidateTextureParameters( - ErrorState* error_state, const char* function_name, - GLenum target, GLenum format, GLenum type, GLint level) { +bool TextureManager::ValidateFormatAndTypeCombination( + ErrorState* error_state, const char* function_name, GLenum format, + GLenum type) { if (!feature_info_->GetTextureFormatValidator(format).IsValid(type)) { - ERRORSTATE_SET_GL_ERROR( - error_state, GL_INVALID_OPERATION, function_name, - (std::string("invalid type ") + - GLES2Util::GetStringEnum(type) + " for format " + - GLES2Util::GetStringEnum(format)).c_str()); - return false; - } - - uint32 channels = GLES2Util::GetChannelsForFormat(format); - if ((channels & (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && level) { ERRORSTATE_SET_GL_ERROR( error_state, GL_INVALID_OPERATION, function_name, (std::string("invalid type ") + @@ -1283,6 +1271,40 @@ bool TextureManager::ValidateTextureParameters( return true; } +bool TextureManager::ValidateTextureParameters( + ErrorState* error_state, const char* function_name, + GLenum format, GLenum type, GLenum internal_format, GLint level) { + const Validators* validators = feature_info_->validators(); + if (!validators->texture_format.IsValid(format)) { + ERRORSTATE_SET_GL_ERROR_INVALID_ENUM( + error_state, function_name, format, "format"); + return false; + } + if (!validators->pixel_type.IsValid(type)) { + ERRORSTATE_SET_GL_ERROR_INVALID_ENUM( + error_state, function_name, type, "type"); + return false; + } + if (format != internal_format && + !((internal_format == GL_RGBA32F && format == GL_RGBA) || + (internal_format == GL_RGB32F && format == GL_RGB))) { + ERRORSTATE_SET_GL_ERROR( + error_state, GL_INVALID_OPERATION, function_name, + "format != internalformat"); + return false; + } + uint32 channels = GLES2Util::GetChannelsForFormat(format); + if ((channels & (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && level) { + ERRORSTATE_SET_GL_ERROR( + error_state, GL_INVALID_OPERATION, function_name, + (std::string("invalid format ") + GLES2Util::GetStringEnum(format) + + " for level != 0").c_str()); + return false; + } + return ValidateFormatAndTypeCombination(error_state, function_name, + format, type); +} + // Gets the texture id for a given target. TextureRef* TextureManager::GetTextureInfoForTarget( ContextState* state, GLenum target) { @@ -1336,31 +1358,15 @@ bool TextureManager::ValidateTexImage2D( error_state, function_name, args.target, "target"); return false; } - if (!validators->texture_format.IsValid(args.internal_format)) { + if (!validators->texture_internal_format.IsValid(args.internal_format)) { ERRORSTATE_SET_GL_ERROR_INVALID_ENUM( error_state, function_name, args.internal_format, - "internal_format"); - return false; - } - if (!validators->texture_format.IsValid(args.format)) { - ERRORSTATE_SET_GL_ERROR_INVALID_ENUM( - error_state, function_name, args.format, "format"); - return false; - } - if (!validators->pixel_type.IsValid(args.type)) { - ERRORSTATE_SET_GL_ERROR_INVALID_ENUM( - error_state, function_name, args.type, "type"); - return false; - } - if (args.format != args.internal_format) { - ERRORSTATE_SET_GL_ERROR( - error_state, GL_INVALID_OPERATION, function_name, - "format != internalFormat"); + "internalformat"); return false; } if (!ValidateTextureParameters( - error_state, function_name, args.target, args.format, args.type, - args.level)) { + error_state, function_name, args.format, args.type, + args.internal_format, args.level)) { return false; } if (!ValidForTarget(args.target, args.level, args.width, args.height, 1) || @@ -1396,7 +1402,7 @@ bool TextureManager::ValidateTexImage2D( // They both use the same MemoryTracker, and this call just re-routes // to it. if (!memory_tracker_managed_->EnsureGPUMemoryAvailable(args.pixels_size)) { - ERRORSTATE_SET_GL_ERROR(error_state, GL_OUT_OF_MEMORY, "glTexImage2D", + ERRORSTATE_SET_GL_ERROR(error_state, GL_OUT_OF_MEMORY, function_name, "out of memory"); return false; } diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h index b74ef91..c44bef3 100644 --- a/gpu/command_buffer/service/texture_manager.h +++ b/gpu/command_buffer/service/texture_manager.h @@ -116,7 +116,7 @@ class GPU_EXPORT Texture { } // Returns true of the given dimensions are inside the dimensions of the - // level and if the format and type match the level. + // level and if the type matches the level. bool ValidForTexture( GLint target, GLint level, @@ -124,7 +124,6 @@ class GPU_EXPORT Texture { GLint yoffset, GLsizei width, GLsizei height, - GLenum format, GLenum type) const; bool IsValid() const { @@ -707,9 +706,15 @@ class GPU_EXPORT TextureManager { TextureRef* GetTextureInfoForTargetUnlessDefault( ContextState* state, GLenum target); + bool ValidateFormatAndTypeCombination( + ErrorState* error_state, const char* function_name, + GLenum format, GLenum type); + + // Note that internal_format is only checked in relation to the format + // parameter, so that this function may be used to validate texSubImage2D. bool ValidateTextureParameters( ErrorState* error_state, const char* function_name, - GLenum target, GLenum format, GLenum type, GLint level); + GLenum format, GLenum type, GLenum internal_format, GLint level); private: friend class Texture; diff --git a/gpu/command_buffer/service/texture_manager_unittest.cc b/gpu/command_buffer/service/texture_manager_unittest.cc index 002f2f8..ada24a8 100644 --- a/gpu/command_buffer/service/texture_manager_unittest.cc +++ b/gpu/command_buffer/service/texture_manager_unittest.cc @@ -1042,43 +1042,40 @@ TEST_F(TextureTest, ValidForTexture) { Texture* texture = texture_ref_->texture(); EXPECT_FALSE(texture->ValidForTexture( GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, - 1, 0, 0, 4, 5, GL_RGBA, GL_UNSIGNED_BYTE)); + 1, 0, 0, 4, 5, GL_UNSIGNED_BYTE)); // Check bad level. EXPECT_FALSE(texture->ValidForTexture( - GL_TEXTURE_2D, 0, 0, 0, 4, 5, GL_RGBA, GL_UNSIGNED_BYTE)); + GL_TEXTURE_2D, 0, 0, 0, 4, 5, GL_UNSIGNED_BYTE)); // Check bad xoffset. EXPECT_FALSE(texture->ValidForTexture( - GL_TEXTURE_2D, 1, -1, 0, 4, 5, GL_RGBA, GL_UNSIGNED_BYTE)); + GL_TEXTURE_2D, 1, -1, 0, 4, 5, GL_UNSIGNED_BYTE)); // Check bad xoffset + width > width. EXPECT_FALSE(texture->ValidForTexture( - GL_TEXTURE_2D, 1, 1, 0, 4, 5, GL_RGBA, GL_UNSIGNED_BYTE)); + GL_TEXTURE_2D, 1, 1, 0, 4, 5, GL_UNSIGNED_BYTE)); // Check bad yoffset. EXPECT_FALSE(texture->ValidForTexture( - GL_TEXTURE_2D, 1, 0, -1, 4, 5, GL_RGBA, GL_UNSIGNED_BYTE)); + GL_TEXTURE_2D, 1, 0, -1, 4, 5, GL_UNSIGNED_BYTE)); // Check bad yoffset + height > height. EXPECT_FALSE(texture->ValidForTexture( - GL_TEXTURE_2D, 1, 0, 1, 4, 5, GL_RGBA, GL_UNSIGNED_BYTE)); + GL_TEXTURE_2D, 1, 0, 1, 4, 5, GL_UNSIGNED_BYTE)); // Check bad width. EXPECT_FALSE(texture->ValidForTexture( - GL_TEXTURE_2D, 1, 0, 0, 5, 5, GL_RGBA, GL_UNSIGNED_BYTE)); + GL_TEXTURE_2D, 1, 0, 0, 5, 5, GL_UNSIGNED_BYTE)); // Check bad height. EXPECT_FALSE(texture->ValidForTexture( - GL_TEXTURE_2D, 1, 0, 0, 4, 6, GL_RGBA, GL_UNSIGNED_BYTE)); - // Check bad format. - EXPECT_FALSE(texture->ValidForTexture( - GL_TEXTURE_2D, 1, 0, 0, 4, 5, GL_RGB, GL_UNSIGNED_BYTE)); + GL_TEXTURE_2D, 1, 0, 0, 4, 6, GL_UNSIGNED_BYTE)); // Check bad type. EXPECT_FALSE(texture->ValidForTexture( - GL_TEXTURE_2D, 1, 0, 0, 4, 5, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4)); + GL_TEXTURE_2D, 1, 0, 0, 4, 5, GL_UNSIGNED_SHORT_4_4_4_4)); // Check valid full size EXPECT_TRUE(texture->ValidForTexture( - GL_TEXTURE_2D, 1, 0, 0, 4, 5, GL_RGBA, GL_UNSIGNED_BYTE)); + GL_TEXTURE_2D, 1, 0, 0, 4, 5, GL_UNSIGNED_BYTE)); // Check valid particial size. EXPECT_TRUE(texture->ValidForTexture( - GL_TEXTURE_2D, 1, 1, 1, 2, 3, GL_RGBA, GL_UNSIGNED_BYTE)); + GL_TEXTURE_2D, 1, 1, 1, 2, 3, GL_UNSIGNED_BYTE)); manager_->RemoveTexture(kClient1Id); EXPECT_TRUE(texture->ValidForTexture( - GL_TEXTURE_2D, 1, 0, 0, 4, 5, GL_RGBA, GL_UNSIGNED_BYTE)); + GL_TEXTURE_2D, 1, 0, 0, 4, 5, GL_UNSIGNED_BYTE)); } TEST_F(TextureTest, FloatNotLinear) { diff --git a/ui/gl/gl_context.cc b/ui/gl/gl_context.cc index dc3a3e8..cd9a28c 100644 --- a/ui/gl/gl_context.cc +++ b/ui/gl/gl_context.cc @@ -66,6 +66,13 @@ std::string GLContext::GetGLVersion() { return std::string(version ? version : ""); } +std::string GLContext::GetGLRenderer() { + DCHECK(IsCurrent(NULL)); + const char *renderer = + reinterpret_cast<const char*>(glGetString(GL_RENDERER)); + return std::string(renderer ? renderer : ""); +} + bool GLContext::HasExtension(const char* name) { std::string extensions = GetExtensions(); extensions += " "; @@ -79,8 +86,9 @@ bool GLContext::HasExtension(const char* name) { const GLVersionInfo* GLContext::GetVersionInfo() { if(!version_info_) { std::string version = GetGLVersion(); + std::string renderer = GetGLRenderer(); version_info_ = scoped_ptr<GLVersionInfo>( - new GLVersionInfo(version.c_str())); + new GLVersionInfo(version.c_str(), renderer.c_str())); } return version_info_.get(); } diff --git a/ui/gl/gl_context.h b/ui/gl/gl_context.h index 66a7631..f40b1bb 100644 --- a/ui/gl/gl_context.h +++ b/ui/gl/gl_context.h @@ -108,6 +108,12 @@ class GL_EXPORT GLContext : public base::RefCounted<GLContext> { // being released or destroyed. void OnReleaseVirtuallyCurrent(GLContext* virtual_context); + // Returns the GL version string. The context must be current. + virtual std::string GetGLVersion(); + + // Returns the GL renderer string. The context must be current. + virtual std::string GetGLRenderer(); + protected: virtual ~GLContext(); @@ -123,9 +129,6 @@ class GL_EXPORT GLContext : public base::RefCounted<GLContext> { // Returns the last real (non-virtual) GLContext made current. static GLContext* GetRealCurrent(); - // Returns the GL version string. The context must be current. - virtual std::string GetGLVersion(); - private: friend class base::RefCounted<GLContext>; diff --git a/ui/gl/gl_context_stub.cc b/ui/gl/gl_context_stub.cc index 56fb3c7..1d39d3e 100644 --- a/ui/gl/gl_context_stub.cc +++ b/ui/gl/gl_context_stub.cc @@ -39,6 +39,10 @@ std::string GLContextStub::GetExtensions() { return std::string(); } +std::string GLContextStub::GetGLRenderer() { + return std::string("CHROMIUM"); +} + GLContextStub::~GLContextStub() {} } // namespace gfx diff --git a/ui/gl/gl_context_stub.h b/ui/gl/gl_context_stub.h index 8fca5b7..d57e02e 100644 --- a/ui/gl/gl_context_stub.h +++ b/ui/gl/gl_context_stub.h @@ -24,6 +24,7 @@ class GL_EXPORT GLContextStub : public GLContextReal { virtual void* GetHandle() OVERRIDE; virtual void SetSwapInterval(int interval) OVERRIDE; virtual std::string GetExtensions() OVERRIDE; + virtual std::string GetGLRenderer() OVERRIDE; protected: virtual ~GLContextStub(); diff --git a/ui/gl/gl_gl_api_implementation.cc b/ui/gl/gl_gl_api_implementation.cc index 9184fc3..fe98fba 100644 --- a/ui/gl/gl_gl_api_implementation.cc +++ b/ui/gl/gl_gl_api_implementation.cc @@ -14,6 +14,7 @@ #include "ui/gl/gl_state_restorer.h" #include "ui/gl/gl_surface.h" #include "ui/gl/gl_switches.h" +#include "ui/gl/gl_version_info.h" namespace gfx { @@ -23,6 +24,8 @@ static GLApi* g_gl; static RealGLApi* g_real_gl; // A GL Api that calls TRACE and then calls another GL api. static TraceGLApi* g_trace_gl; +// GL version used when initializing dynamic bindings. +static GLVersionInfo* g_version_info = NULL; namespace { @@ -40,7 +43,28 @@ static inline GLenum GetTexInternalFormat(GLenum internal_format, GLenum type) { GLenum gl_internal_format = GetInternalFormat(internal_format); - if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2) + // g_version_info must be initialized when this function is bound. + DCHECK(gfx::g_version_info); + if (type == GL_FLOAT && gfx::g_version_info->is_angle && + gfx::g_version_info->is_es2) { + // It's possible that the texture is using a sized internal format, and + // ANGLE exposing GLES2 API doesn't support those. + // TODO(oetuaho@nvidia.com): Remove these conversions once ANGLE has the + // support. + // http://code.google.com/p/angleproject/issues/detail?id=556 + switch (format) { + case GL_RGBA: + gl_internal_format = GL_RGBA; + break; + case GL_RGB: + gl_internal_format = GL_RGB; + break; + default: + break; + } + } + + if (gfx::g_version_info->is_es) return gl_internal_format; if (type == GL_FLOAT) { @@ -208,6 +232,9 @@ void SetGLToRealGLApi() { void InitializeDynamicGLBindingsGL(GLContext* context) { g_driver_gl.InitializeCustomDynamicBindings(context); + DCHECK(context && context->IsCurrent(NULL) && !g_version_info); + g_version_info = new GLVersionInfo(context->GetGLVersion().c_str(), + context->GetGLRenderer().c_str()); } void InitializeDebugGLBindingsGL() { @@ -233,6 +260,10 @@ void ClearGLBindingsGL() { delete g_current_gl_context_tls; g_current_gl_context_tls = NULL; } + if (g_version_info) { + delete g_version_info; + g_version_info = NULL; + } } GLApi::GLApi() { diff --git a/ui/gl/gl_version_info.cc b/ui/gl/gl_version_info.cc index a45219a..996c44f 100644 --- a/ui/gl/gl_version_info.cc +++ b/ui/gl/gl_version_info.cc @@ -8,7 +8,7 @@ namespace gfx { -GLVersionInfo::GLVersionInfo(const char* version_str) +GLVersionInfo::GLVersionInfo(const char* version_str, const char* renderer_str) : is_es(false), is_es1(false), is_es2(false), @@ -16,7 +16,8 @@ GLVersionInfo::GLVersionInfo(const char* version_str) is_gl1(false), is_gl2(false), is_gl3(false), - is_gl4(false) { + is_gl4(false), + is_angle(false) { if (version_str) { std::string lstr(StringToLowerASCII(std::string(version_str))); is_es = (lstr.substr(0, 9) == "opengl es"); @@ -33,6 +34,9 @@ GLVersionInfo::GLVersionInfo(const char* version_str) is_gl1 = !is_gl2 && !is_gl3 && !is_gl4; } } + if (renderer_str) { + is_angle = StartsWithASCII(renderer_str, "ANGLE", true); + } } } // namespace gfx diff --git a/ui/gl/gl_version_info.h b/ui/gl/gl_version_info.h index c8ecb07..13b323f 100644 --- a/ui/gl/gl_version_info.h +++ b/ui/gl/gl_version_info.h @@ -11,7 +11,7 @@ namespace gfx { struct GLVersionInfo { - explicit GLVersionInfo(const char* version_str); + GLVersionInfo(const char* version_str, const char* renderer_str); // New flags, such as is_gl4_4 could be introduced as needed. // For now, this level of granularity is enough. @@ -25,6 +25,8 @@ struct GLVersionInfo { bool is_gl3; bool is_gl4; + bool is_angle; + private: DISALLOW_COPY_AND_ASSIGN(GLVersionInfo); }; |