diff options
author | kbr@chromium.org <kbr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-23 22:21:46 +0000 |
---|---|---|
committer | kbr@chromium.org <kbr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-23 22:21:46 +0000 |
commit | e51bdf3d4f7bb89497344af0b4a99ff10512c0d5 (patch) | |
tree | f8ea1734e59c778c3acc8b9a4454789c526f15bd /gpu | |
parent | b898f0108b4e39bb86577455470dd42490ff1b7b (diff) | |
download | chromium_src-e51bdf3d4f7bb89497344af0b4a99ff10512c0d5.zip chromium_src-e51bdf3d4f7bb89497344af0b4a99ff10512c0d5.tar.gz chromium_src-e51bdf3d4f7bb89497344af0b4a99ff10512c0d5.tar.bz2 |
Added minimal support to command buffer for GL_ARB_texture_rectangle
textures, and added Mac OS X-specific extension for binding IOSurfaces
to textures. This is infrastructure work for rendering Core Animation
plugins via Chrome's compositor.
Refactored the texture initialization in the command buffer and
associated unit tests. Added unit tests for rectangular textures.
These changes will be hooked up in a subsequent CL. They were split
off for easier review.
There are ongoing discussions about unifying the various mechanisms
for sharing textures across processes, but it's been agreed that those
should not block this work.
BUG=38967
TEST=GPU unit tests; manual testing with forthcoming changes
Review URL: http://codereview.chromium.org/8680002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@111426 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu')
22 files changed, 819 insertions, 132 deletions
diff --git a/gpu/GLES2/gl2ext.h b/gpu/GLES2/gl2ext.h index 0d4f788..4ddf729 100644 --- a/gpu/GLES2/gl2ext.h +++ b/gpu/GLES2/gl2ext.h @@ -1401,6 +1401,41 @@ GL_APICALL void GL_APIENTRY glGetTranslatedShaderSourceANGLE (GLuint shader, GLs typedef void (GL_APIENTRYP PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC) (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source); #endif +/* GL_ARB_texture_rectangle */ +/* Exposes only the subset necessary to support GL_CHROMIUM_iosurface. + */ +#ifndef GL_ARB_texture_rectangle +#define GL_ARB_texture_rectangle 1 +#ifndef GL_TEXTURE_RECTANGLE_ARB +#define GL_TEXTURE_RECTANGLE_ARB 0x84F5 +#endif +#ifndef GL_TEXTURE_BINDING_RECTANGLE_ARB +#define GL_TEXTURE_BINDING_RECTANGLE_ARB 0x84F6 +#endif +#ifndef GL_SAMPLER_2D_RECT_ARB +#define GL_SAMPLER_2D_RECT_ARB 0x8B63 +#endif +#endif + +/* GL_CHROMIUM_iosurface */ +/* Exposes the Mac OS-specfic CGLTexImageIOSurface2D entry point as a + * Chromium extension in the cross-platform API. Binds the IOSurface with + * the given ID (an IOSurfaceID) to the texture bound to the given target. + * To avoid needing to expose extraneous enums, assumes internal format + * RGBA, format BGRA, and type UNSIGNED_INT_8_8_8_8_REV. + */ +#ifndef GL_CHROMIUM_iosurface +#define GL_CHROMIUM_iosurface 1 +#ifdef GL_GLEXT_PROTOTYPES +#define glTexImageIOSurface2DCHROMIUM GLES2_GET_FUN(TexImageIOSurface2DCHROMIUM) +#if !defined(GLES2_USE_CPP_BINDINGS) +GL_APICALL void GL_APIENTRY glTexImageIOSurface2DCHROMIUM (GLenum target, GLsizei width, GLsizei height, GLuint ioSurfaceId, GLuint plane); +#endif +#else +typedef void (GL_APIENTRYP PFNGLTEXIMAGEIOSURFACE2DCHROMIUM) (GLenum target, GLsizei width, GLsizei height, GLuint ioSurfaceId, GLuint plane); +#endif +#endif + #ifdef __cplusplus } #endif diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py index 36dad3f..7d00e42 100755 --- a/gpu/command_buffer/build_gles2_cmd_buffer.py +++ b/gpu/command_buffer/build_gles2_cmd_buffer.py @@ -225,6 +225,7 @@ GL_APICALL void GL_APIENTRY glDestroyStreamTextureCHROMIUM (GLuint textu GL_APICALL void GL_APIENTRY glPlaceholder453CHROMIUM (void); GL_APICALL void GL_APIENTRY glGetTranslatedShaderSourceANGLE (GLidShader shader, GLsizeiNotNegative bufsize, GLsizei* length, char* source); GL_APICALL void GL_APIENTRY glPostSubBufferCHROMIUM (GLint x, GLint y, GLint width, GLint height); +GL_APICALL void GL_APIENTRY glTexImageIOSurface2DCHROMIUM (GLenumTextureBindTarget target, GLsizei width, GLsizei height, GLuint ioSurfaceId, GLuint plane); """ # This is the list of all commmands that will be generated and their Id. @@ -435,6 +436,7 @@ _CMD_ID_TABLE = { 'GetProgramInfoCHROMIUM': 455, 'GetTranslatedShaderSourceANGLE': 456, 'PostSubBufferCHROMIUM': 457, + 'TexImageIOSurface2DCHROMIUM': 458, } # This is a list of enum names and their valid values. It is used to map @@ -1793,6 +1795,12 @@ _FUNCTION_INFO = { 'extension': True, 'chromium': True, }, + 'TexImageIOSurface2DCHROMIUM': { + 'decoder_func': 'DoTexImageIOSurface2DCHROMIUM', + 'unit_test': False, + 'extension': True, + 'chromium': True, + }, } diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h index 40c7102..d7fde69 100644 --- a/gpu/command_buffer/client/gles2_c_lib_autogen.h +++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h @@ -589,6 +589,12 @@ void GLES2GetTranslatedShaderSourceANGLE( void GLES2PostSubBufferCHROMIUM(GLint x, GLint y, GLint width, GLint height) { gles2::GetGLContext()->PostSubBufferCHROMIUM(x, y, width, height); } +void GLES2TexImageIOSurface2DCHROMIUM( + GLenum target, GLsizei width, GLsizei height, GLuint ioSurfaceId, + GLuint plane) { + gles2::GetGLContext()->TexImageIOSurface2DCHROMIUM( + target, width, height, ioSurfaceId, plane); +} #endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_C_LIB_AUTOGEN_H_ diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h index 2a5d6d7..8e1ec4e 100644 --- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h +++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h @@ -1253,5 +1253,13 @@ c.Init(x, y, width, height); } + void TexImageIOSurface2DCHROMIUM( + GLenum target, GLsizei width, GLsizei height, GLuint ioSurfaceId, + GLuint plane) { + gles2::TexImageIOSurface2DCHROMIUM& c = + GetCmdSpace<gles2::TexImageIOSurface2DCHROMIUM>(); + c.Init(target, width, height, ioSurfaceId, plane); + } + #endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_CMD_HELPER_AUTOGEN_H_ diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h index 0721c79..978abf8 100644 --- a/gpu/command_buffer/client/gles2_implementation_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_autogen.h @@ -1305,5 +1305,21 @@ void GetTranslatedShaderSourceANGLE( } void PostSubBufferCHROMIUM(GLint x, GLint y, GLint width, GLint height); +void TexImageIOSurface2DCHROMIUM( + GLenum target, GLsizei width, GLsizei height, GLuint ioSurfaceId, + GLuint plane) { + GPU_CLIENT_LOG("[" << this << "] glTexImageIOSurface2DCHROMIUM(" << GLES2Util::GetStringTextureBindTarget(target) << ", " << width << ", " << height << ", " << ioSurfaceId << ", " << plane << ")"); // NOLINT + if (width < 0) { + SetGLError(GL_INVALID_VALUE, "glTexImageIOSurface2DCHROMIUM: width < 0"); + return; + } + if (height < 0) { + SetGLError(GL_INVALID_VALUE, "glTexImageIOSurface2DCHROMIUM: height < 0"); + return; + } + helper_->TexImageIOSurface2DCHROMIUM( + target, width, height, ioSurfaceId, plane); +} + #endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_AUTOGEN_H_ diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h index cb54dda..2e726f4 100644 --- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h @@ -9211,6 +9211,61 @@ COMPILE_ASSERT(offsetof(PostSubBufferCHROMIUM, width) == 12, COMPILE_ASSERT(offsetof(PostSubBufferCHROMIUM, height) == 16, OffsetOf_PostSubBufferCHROMIUM_height_not_16); +struct TexImageIOSurface2DCHROMIUM { + typedef TexImageIOSurface2DCHROMIUM ValueType; + static const CommandId kCmdId = kTexImageIOSurface2DCHROMIUM; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + + static uint32 ComputeSize() { + return static_cast<uint32>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { + header.SetCmd<ValueType>(); + } + + void Init( + GLenum _target, GLsizei _width, GLsizei _height, GLuint _ioSurfaceId, + GLuint _plane) { + SetHeader(); + target = _target; + width = _width; + height = _height; + ioSurfaceId = _ioSurfaceId; + plane = _plane; + } + + void* Set( + void* cmd, GLenum _target, GLsizei _width, GLsizei _height, + GLuint _ioSurfaceId, GLuint _plane) { + static_cast<ValueType*>( + cmd)->Init(_target, _width, _height, _ioSurfaceId, _plane); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32 target; + int32 width; + int32 height; + uint32 ioSurfaceId; + uint32 plane; +}; + +COMPILE_ASSERT(sizeof(TexImageIOSurface2DCHROMIUM) == 24, + Sizeof_TexImageIOSurface2DCHROMIUM_is_not_24); +COMPILE_ASSERT(offsetof(TexImageIOSurface2DCHROMIUM, header) == 0, + OffsetOf_TexImageIOSurface2DCHROMIUM_header_not_0); +COMPILE_ASSERT(offsetof(TexImageIOSurface2DCHROMIUM, target) == 4, + OffsetOf_TexImageIOSurface2DCHROMIUM_target_not_4); +COMPILE_ASSERT(offsetof(TexImageIOSurface2DCHROMIUM, width) == 8, + OffsetOf_TexImageIOSurface2DCHROMIUM_width_not_8); +COMPILE_ASSERT(offsetof(TexImageIOSurface2DCHROMIUM, height) == 12, + OffsetOf_TexImageIOSurface2DCHROMIUM_height_not_12); +COMPILE_ASSERT(offsetof(TexImageIOSurface2DCHROMIUM, ioSurfaceId) == 16, + OffsetOf_TexImageIOSurface2DCHROMIUM_ioSurfaceId_not_16); +COMPILE_ASSERT(offsetof(TexImageIOSurface2DCHROMIUM, plane) == 20, + OffsetOf_TexImageIOSurface2DCHROMIUM_plane_not_20); + #endif // GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_AUTOGEN_H_ diff --git a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h index 9c414a9..9028708 100644 --- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h @@ -3578,5 +3578,27 @@ TEST_F(GLES2FormatTest, PostSubBufferCHROMIUM) { next_cmd, sizeof(cmd)); } +TEST_F(GLES2FormatTest, TexImageIOSurface2DCHROMIUM) { + TexImageIOSurface2DCHROMIUM& cmd = + *GetBufferAs<TexImageIOSurface2DCHROMIUM>(); + void* next_cmd = cmd.Set( + &cmd, + static_cast<GLenum>(11), + static_cast<GLsizei>(12), + static_cast<GLsizei>(13), + static_cast<GLuint>(14), + static_cast<GLuint>(15)); + EXPECT_EQ(static_cast<uint32>(TexImageIOSurface2DCHROMIUM::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLenum>(11), cmd.target); + EXPECT_EQ(static_cast<GLsizei>(12), cmd.width); + EXPECT_EQ(static_cast<GLsizei>(13), cmd.height); + EXPECT_EQ(static_cast<GLuint>(14), cmd.ioSurfaceId); + EXPECT_EQ(static_cast<GLuint>(15), cmd.plane); + CheckBytesWrittenMatchesExpectedSize( + next_cmd, sizeof(cmd)); +} + #endif // GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_TEST_AUTOGEN_H_ diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h index 498c625..6c01a6c 100644 --- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h @@ -212,6 +212,7 @@ OP(GetProgramInfoCHROMIUM) /* 455 */ \ OP(GetTranslatedShaderSourceANGLE) /* 456 */ \ OP(PostSubBufferCHROMIUM) /* 457 */ \ + OP(TexImageIOSurface2DCHROMIUM) /* 458 */ \ enum CommandId { kStartPoint = cmd::kLastCommonId, // All GLES2 commands start after this. diff --git a/gpu/command_buffer/common/gles2_cmd_utils.cc b/gpu/command_buffer/common/gles2_cmd_utils.cc index 5834d2a0..22763b6 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils.cc +++ b/gpu/command_buffer/common/gles2_cmd_utils.cc @@ -195,6 +195,8 @@ int GLES2Util::GLGetNumValuesReturned(int id) const { return 1; case GL_TEXTURE_BINDING_EXTERNAL_OES: return 1; + case GL_TEXTURE_BINDING_RECTANGLE_ARB: + return 1; case GL_UNPACK_ALIGNMENT: return 1; case GL_VIEWPORT: diff --git a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h index 9b8d22b..72ddb4a 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h @@ -129,6 +129,7 @@ static GLES2Util::EnumToString enum_to_string_table[] = { { 0x84FE, "GL_TEXTURE_MAX_ANISOTROPY_EXT", }, { 0x0901, "GL_CCW", }, { 0x0900, "GL_CW", }, + { 0x8B63, "GL_SAMPLER_2D_RECT_ARB", }, { 0x8B60, "GL_SAMPLER_CUBE", }, { 0x00001000, "GL_DEPTH_BUFFER_BIT4_QCOM", }, { 0x00000080, "GL_COLOR_BUFFER_BIT7_QCOM", }, @@ -164,8 +165,10 @@ static GLES2Util::EnumToString enum_to_string_table[] = { { 0x813D, "GL_TEXTURE_MAX_LEVEL_APPLE", }, { 0x8CDD, "GL_FRAMEBUFFER_UNSUPPORTED", }, { 0x8CDF, "GL_MAX_COLOR_ATTACHMENTS_NV", }, + { 0x84F5, "GL_TEXTURE_RECTANGLE_ARB", }, { 0x882A, "GL_DRAW_BUFFER5_NV", }, { 0x80AA, "GL_SAMPLE_COVERAGE_VALUE", }, + { 0x84F6, "GL_TEXTURE_BINDING_RECTANGLE_ARB", }, { 0x80AB, "GL_SAMPLE_COVERAGE_INVERT", }, { 0x882B, "GL_DRAW_BUFFER6_NV", }, { 0x882C, "GL_DRAW_BUFFER7_NV", }, diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc index 6b26b91..66c05a8 100644 --- a/gpu/command_buffer/service/feature_info.cc +++ b/gpu/command_buffer/service/feature_info.cc @@ -8,6 +8,9 @@ #include "gpu/command_buffer/service/gl_utils.h" #include "ui/gfx/gl/gl_context.h" #include "ui/gfx/gl/gl_implementation.h" +#if defined(OS_MACOSX) +#include "ui/gfx/surface/io_surface_support_mac.h" +#endif namespace gpu { namespace gles2 { @@ -354,6 +357,30 @@ void FeatureInfo::AddFeatures(const char* desired_features) { feature_flags_.chromium_stream_texture = true; } + // Ideally we would only expose this extension on Mac OS X, to + // support GL_CHROMIUM_iosurface and the compositor. We don't want + // applications to start using it; they should use ordinary non- + // power-of-two textures. However, for unit testing purposes we + // expose it on all supported platforms. + if (ext.HaveAndDesire("GL_ARB_texture_rectangle")) { + AddExtensionString("GL_ARB_texture_rectangle"); + feature_flags_.arb_texture_rectangle = true; + validators_.texture_bind_target.AddValue(GL_TEXTURE_RECTANGLE_ARB); + // For the moment we don't add this enum to the texture_target + // validator. This implies that the only way to get image data into a + // rectangular texture is via glTexImageIOSurface2DCHROMIUM, which is + // just fine since again we don't want applications depending on this + // extension. + validators_.get_tex_param_target.AddValue(GL_TEXTURE_RECTANGLE_ARB); + validators_.g_l_state.AddValue(GL_TEXTURE_BINDING_RECTANGLE_ARB); + } + +#if defined(OS_MACOSX) + if (IOSurfaceSupport::Initialize()) { + AddExtensionString("GL_CHROMIUM_iosurface"); + } +#endif + // TODO(gman): Add support for these extensions. // GL_OES_depth32 // GL_OES_element_index_uint diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h index 485cbc9..fb4177b 100644 --- a/gpu/command_buffer/service/feature_info.h +++ b/gpu/command_buffer/service/feature_info.h @@ -25,7 +25,8 @@ class FeatureInfo { enable_texture_half_float_linear(false), chromium_webglsl(false), chromium_stream_texture(false), - angle_translated_shader_source(false) { + angle_translated_shader_source(false), + arb_texture_rectangle(false) { } bool chromium_framebuffer_multisample; @@ -37,6 +38,7 @@ class FeatureInfo { bool chromium_webglsl; bool chromium_stream_texture; bool angle_translated_shader_source; + bool arb_texture_rectangle; }; FeatureInfo(); diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 70c7484..6ba84f9 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -15,6 +15,9 @@ #include "base/atomicops.h" #include "base/at_exit.h" #include "base/bind.h" +#if defined(OS_MACOSX) +#include "base/mac/scoped_cftyperef.h" +#endif #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "build/build_config.h" @@ -41,6 +44,9 @@ #include "ui/gfx/gl/gl_context.h" #include "ui/gfx/gl/gl_implementation.h" #include "ui/gfx/gl/gl_surface.h" +#if defined(OS_MACOSX) +#include "ui/gfx/surface/io_surface_support_mac.h" +#endif #if !defined(GL_DEPTH24_STENCIL8) #define GL_DEPTH24_STENCIL8 0x88F0 @@ -560,12 +566,26 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, // glBindTexture TextureManager::TextureInfo::Ref bound_texture_external_oes; + // texture currently bound to this unit's GL_TEXTURE_RECTANGLE_ARB with + // glBindTexture + TextureManager::TextureInfo::Ref bound_texture_rectangle_arb; + TextureManager::TextureInfo::Ref GetInfoForSamplerType(GLenum type) { DCHECK(type == GL_SAMPLER_2D || type == GL_SAMPLER_CUBE || - type == GL_SAMPLER_EXTERNAL_OES); - return type == GL_SAMPLER_2D ? bound_texture_2d : - (type == GL_SAMPLER_EXTERNAL_OES ? bound_texture_external_oes : - bound_texture_cube_map); + type == GL_SAMPLER_EXTERNAL_OES || type == GL_SAMPLER_2D_RECT_ARB); + switch (type) { + case GL_SAMPLER_2D: + return bound_texture_2d; + case GL_SAMPLER_CUBE: + return bound_texture_cube_map; + case GL_SAMPLER_EXTERNAL_OES: + return bound_texture_external_oes; + case GL_SAMPLER_2D_RECT_ARB: + return bound_texture_rectangle_arb; + } + + NOTREACHED(); + return NULL; } void Unbind(TextureManager::TextureInfo* texture) { @@ -723,6 +743,14 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, GLenum type, const void * data); + // Wrapper for TexImageIOSurface2DCHROMIUM. + void DoTexImageIOSurface2DCHROMIUM( + GLenum target, + GLsizei width, + GLsizei height, + GLuint io_surface_id, + GLuint plane); + // Creates a ProgramInfo for the given program. ProgramManager::ProgramInfo* CreateProgramInfo( GLuint client_id, GLuint service_id) { @@ -1181,10 +1209,9 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, case GL_TEXTURE_EXTERNAL_OES: info = unit.bound_texture_external_oes; break; - // Note: If we ever support TEXTURE_RECTANGLE as a target, be sure to - // track |texture_| with the currently bound TEXTURE_RECTANGLE texture, - // because |texture_| is used by the FBO rendering mechanism for readback - // to the bits that get sent to the browser. + case GL_TEXTURE_RECTANGLE_ARB: + info = unit.bound_texture_rectangle_arb; + break; default: NOTREACHED(); return NULL; @@ -1194,10 +1221,20 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, GLenum GetBindTargetForSamplerType(GLenum type) { DCHECK(type == GL_SAMPLER_2D || type == GL_SAMPLER_CUBE || - type == GL_SAMPLER_EXTERNAL_OES); - return type == GL_SAMPLER_2D ? GL_TEXTURE_2D : - (type == GL_SAMPLER_EXTERNAL_OES ? GL_TEXTURE_EXTERNAL_OES : - GL_TEXTURE_CUBE_MAP); + type == GL_SAMPLER_EXTERNAL_OES || type == GL_SAMPLER_2D_RECT_ARB); + switch (type) { + case GL_SAMPLER_2D: + return GL_TEXTURE_2D; + case GL_SAMPLER_CUBE: + return GL_TEXTURE_CUBE_MAP; + case GL_SAMPLER_EXTERNAL_OES: + return GL_TEXTURE_EXTERNAL_OES; + case GL_SAMPLER_2D_RECT_ARB: + return GL_TEXTURE_RECTANGLE_ARB; + } + + NOTREACHED(); + return 0; } // Gets the framebuffer info for a particular target. @@ -1245,6 +1282,10 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, // Returns true if the context was just lost due to e.g. GL_ARB_robustness. bool WasContextLost(); +#if defined(OS_MACOSX) + void ReleaseIOSurfaceForTexture(GLuint texture_id); +#endif + // Generate a member function prototype for each command in an automated and // typesafe way. #define GLES2_CMD_OP(name) \ @@ -1422,6 +1463,11 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, bool force_webgl_glsl_validation_; bool derivatives_explicitly_enabled_; +#if defined(OS_MACOSX) + typedef std::map<GLuint, CFTypeRef> TextureToIOSurfaceMap; + TextureToIOSurfaceMap texture_to_io_surface_map_; +#endif + DISALLOW_COPY_AND_ASSIGN(GLES2DecoderImpl); }; @@ -1883,6 +1929,11 @@ bool GLES2DecoderImpl::Initialize( texture_units_[tt].bound_texture_external_oes = info; glBindTexture(GL_TEXTURE_EXTERNAL_OES, info->service_id()); } + if (feature_info_->feature_flags().arb_texture_rectangle) { + info = texture_manager()->GetDefaultTextureInfo(GL_TEXTURE_RECTANGLE_ARB); + texture_units_[tt].bound_texture_rectangle_arb = info; + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, info->service_id()); + } info = texture_manager()->GetDefaultTextureInfo(GL_TEXTURE_CUBE_MAP); texture_units_[tt].bound_texture_cube_map = info; glBindTexture(GL_TEXTURE_CUBE_MAP, info->service_id()); @@ -2103,6 +2154,8 @@ bool GLES2DecoderImpl::InitializeShaderTranslator() { } else { resources.OES_standard_derivatives = feature_info_->feature_flags().oes_standard_derivatives ? 1 : 0; + resources.ARB_texture_rectangle = + feature_info_->feature_flags().arb_texture_rectangle ? 1 : 0; } vertex_translator_.reset(new ShaderTranslator); @@ -2306,6 +2359,11 @@ void GLES2DecoderImpl::DeleteTexturesHelper( if (texture->IsStreamTexture() && stream_texture_manager_) { stream_texture_manager_->DestroyStreamTexture(service_id); } +#if defined(OS_MACOSX) + if (texture->target() == GL_TEXTURE_RECTANGLE_ARB) { + ReleaseIOSurfaceForTexture(service_id); + } +#endif glDeleteTextures(1, &service_id); RemoveTextureInfo(client_ids[ii]); } @@ -2618,6 +2676,14 @@ void GLES2DecoderImpl::Destroy() { offscreen_saved_color_texture_.reset(); offscreen_resolved_frame_buffer_.reset(); offscreen_resolved_color_texture_.reset(); + +#if defined(OS_MACOSX) + for (TextureToIOSurfaceMap::iterator it = texture_to_io_surface_map_.begin(); + it != texture_to_io_surface_map_.end(); ++it) { + CFRelease(it->second); + } + texture_to_io_surface_map_.clear(); +#endif } bool GLES2DecoderImpl::SetParent(GLES2Decoder* new_parent, @@ -3131,6 +3197,9 @@ void GLES2DecoderImpl::DoBindTexture(GLenum target, GLuint client_id) { stream_tex->Update(); } break; + case GL_TEXTURE_RECTANGLE_ARB: + unit.bound_texture_rectangle_arb = info; + break; default: NOTREACHED(); // Validation should prevent us getting here. break; @@ -3473,6 +3542,20 @@ bool GLES2DecoderImpl::GetHelper( } } return true; + case GL_TEXTURE_BINDING_RECTANGLE_ARB: + *num_written = 1; + if (params) { + TextureUnit& unit = texture_units_[active_texture_unit_]; + if (unit.bound_texture_rectangle_arb) { + GLuint client_id = 0; + texture_manager()->GetClientId( + unit.bound_texture_rectangle_arb->service_id(), &client_id); + *params = client_id; + } else { + *params = 0; + } + } + return true; default: *num_written = util_.GLGetNumValuesReturned(pname); return false; @@ -7486,6 +7569,112 @@ error::Error GLES2DecoderImpl::HandleDestroyStreamTextureCHROMIUM( return error::kNoError; } +#if defined(OS_MACOSX) +void GLES2DecoderImpl::ReleaseIOSurfaceForTexture(GLuint texture_id) { + TextureToIOSurfaceMap::iterator it = texture_to_io_surface_map_.find( + texture_id); + if (it != texture_to_io_surface_map_.end()) { + // Found a previous IOSurface bound to this texture; release it. + CFTypeRef surface = it->second; + CFRelease(surface); + texture_to_io_surface_map_.erase(it); + } +} +#endif + +void GLES2DecoderImpl::DoTexImageIOSurface2DCHROMIUM( + GLenum target, GLsizei width, GLsizei height, + GLuint io_surface_id, GLuint plane) { +#if defined(OS_MACOSX) + if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL) { + SetGLError(GL_INVALID_OPERATION, + "glTexImageIOSurface2DCHROMIUM: only supported on desktop GL."); + return; + } + + IOSurfaceSupport* surface_support = IOSurfaceSupport::Initialize(); + if (!surface_support) { + SetGLError(GL_INVALID_OPERATION, + "glTexImageIOSurface2DCHROMIUM: only supported on 10.6."); + return; + } + + if (target != GL_TEXTURE_RECTANGLE_ARB) { + // This might be supported in the future, and if we could require + // support for binding an IOSurface to a NPOT TEXTURE_2D texture, we + // could delete a lot of code. For now, perform strict validation so we + // know what's going on. + SetGLError( + GL_INVALID_OPERATION, + "glTexImageIOSurface2DCHROMIUM: requires TEXTURE_RECTANGLE_ARB target"); + return; + } + + TextureManager::TextureInfo* info = GetTextureInfoForTarget(target); + if (!info) { + SetGLError(GL_INVALID_OPERATION, + "glTexImageIOSurface2DCHROMIUM: no rectangle texture bound"); + return; + } + if (info == texture_manager()->GetDefaultTextureInfo(target)) { + // Maybe this is conceptually valid, but disallow it to avoid accidents. + SetGLError(GL_INVALID_OPERATION, + "glTexImageIOSurface2DCHROMIUM: can't bind default texture"); + return; + } + + // Look up the new IOSurface. Note that because of asynchrony + // between processes this might fail; during live resizing the + // plugin process might allocate and release an IOSurface before + // this process gets a chance to look it up. Hold on to any old + // IOSurface in this case. + CFTypeRef surface = surface_support->IOSurfaceLookup(io_surface_id); + if (!surface) { + SetGLError(GL_INVALID_OPERATION, + "glTexImageIOSurface2DCHROMIUM: no IOSurface with the given ID"); + return; + } + + // Release any IOSurface previously bound to this texture. + ReleaseIOSurfaceForTexture(info->service_id()); + + // Make sure we release the IOSurface even if CGLTexImageIOSurface2D fails. + texture_to_io_surface_map_.insert( + std::make_pair(info->service_id(), surface)); + + CGLContextObj context = + static_cast<CGLContextObj>(context_->GetHandle()); + + CGLError err = surface_support->CGLTexImageIOSurface2D( + context, + target, + GL_RGBA, + width, + height, + GL_BGRA, + GL_UNSIGNED_INT_8_8_8_8_REV, + surface, + plane); + + if (err != kCGLNoError) { + SetGLError( + GL_INVALID_OPERATION, + "glTexImageIOSurface2DCHROMIUM: error in CGLTexImageIOSurface2D"); + return; + } + + texture_manager()->SetLevelInfo( + feature_info_, info, + target, 0, GL_RGBA, width, height, 1, 0, + GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, true); + +#else + SetGLError(GL_INVALID_OPERATION, + "glTexImageIOSurface2DCHROMIUM: not supported."); +#endif +} + + // Include the auto-generated part of this file. We split this because it means // we can easily edit the non-auto generated parts right here in this file // instead of having to edit some template or the code generator. diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h index 680cc28..11a3caf 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h @@ -2576,5 +2576,30 @@ error::Error GLES2DecoderImpl::HandlePlaceholder453CHROMIUM( uint32 immediate_data_size, const gles2::Placeholder453CHROMIUM& c) { return error::kUnknownCommand; } +error::Error GLES2DecoderImpl::HandleTexImageIOSurface2DCHROMIUM( + uint32 immediate_data_size, const gles2::TexImageIOSurface2DCHROMIUM& c) { + GLenum target = static_cast<GLenum>(c.target); + GLsizei width = static_cast<GLsizei>(c.width); + GLsizei height = static_cast<GLsizei>(c.height); + GLuint ioSurfaceId = static_cast<GLuint>(c.ioSurfaceId); + GLuint plane = static_cast<GLuint>(c.plane); + if (!validators_->texture_bind_target.IsValid(target)) { + SetGLError( + GL_INVALID_ENUM, + "glTexImageIOSurface2DCHROMIUM: target GL_INVALID_ENUM"); + return error::kNoError; + } + if (width < 0) { + SetGLError(GL_INVALID_VALUE, "glTexImageIOSurface2DCHROMIUM: width < 0"); + return error::kNoError; + } + if (height < 0) { + SetGLError(GL_INVALID_VALUE, "glTexImageIOSurface2DCHROMIUM: height < 0"); + return error::kNoError; + } + DoTexImageIOSurface2DCHROMIUM(target, width, height, ioSurfaceId, plane); + return error::kNoError; +} + #endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_AUTOGEN_H_ diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc index cb52457..25d96c7 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc @@ -4874,6 +4874,214 @@ TEST_F(GLES2DecoderManualInitTest, StreamTextureCHROMIUMNullMgr) { GetGLError(); // ignore internal error } +TEST_F(GLES2DecoderManualInitTest, ARBTextureRectangleBindTexture) { + InitDecoder( + "GL_ARB_texture_rectangle", // extensions + false, // has alpha + false, // has depth + false, // has stencil + false, // request alpha + false, // request depth + false, // request stencil + true); // bind generates resource + EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_RECTANGLE_ARB, kNewServiceId)); + EXPECT_CALL(*gl_, GenTextures(1, _)) + .WillOnce(SetArgumentPointee<1>(kNewServiceId)); + BindTexture cmd; + cmd.Init(GL_TEXTURE_RECTANGLE_ARB, kNewClientId); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + TextureManager::TextureInfo* info = GetTextureInfo(kNewClientId); + EXPECT_TRUE(info != NULL); + EXPECT_TRUE(info->target() == GL_TEXTURE_RECTANGLE_ARB); +} + +TEST_F(GLES2DecoderManualInitTest, ARBTextureRectangleGetBinding) { + InitDecoder( + "GL_ARB_texture_rectangle", // extensions + false, // has alpha + false, // has depth + false, // has stencil + false, // request alpha + false, // request depth + false, // request stencil + true); // bind generates resource + DoBindTexture( + GL_TEXTURE_RECTANGLE_ARB, client_texture_id_, kServiceTextureId); + + EXPECT_CALL(*gl_, GetError()) + .WillOnce(Return(GL_NO_ERROR)) + .WillOnce(Return(GL_NO_ERROR)) + .RetiresOnSaturation(); + typedef GetIntegerv::Result Result; + Result* result = static_cast<Result*>(shared_memory_address_); + EXPECT_CALL(*gl_, GetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, + result->GetData())) + .Times(0); + result->size = 0; + GetIntegerv cmd; + cmd.Init(GL_TEXTURE_BINDING_RECTANGLE_ARB, + shared_memory_id_, + shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned( + GL_TEXTURE_BINDING_RECTANGLE_ARB), result->GetNumResults()); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + EXPECT_EQ(client_texture_id_, (uint32)result->GetData()[0]); +} + +TEST_F(GLES2DecoderManualInitTest, ARBTextureRectangleTextureDefaults) { + InitDecoder( + "GL_ARB_texture_rectangle", // extensions + false, // has alpha + false, // has depth + false, // has stencil + false, // request alpha + false, // request depth + false, // request stencil + true); // bind generates resource + DoBindTexture( + GL_TEXTURE_RECTANGLE_ARB, client_texture_id_, kServiceTextureId); + + TextureManager::TextureInfo* info = GetTextureInfo(client_texture_id_); + EXPECT_TRUE(info != NULL); + EXPECT_TRUE(info->target() == GL_TEXTURE_RECTANGLE_ARB); + EXPECT_TRUE(info->min_filter() == GL_LINEAR); + EXPECT_TRUE(info->wrap_s() == GL_CLAMP_TO_EDGE); + EXPECT_TRUE(info->wrap_t() == GL_CLAMP_TO_EDGE); +} + +TEST_F(GLES2DecoderManualInitTest, ARBTextureRectangleTextureParam) { + InitDecoder( + "GL_ARB_texture_rectangle", // extensions + false, // has alpha + false, // has depth + false, // has stencil + false, // request alpha + false, // request depth + false, // request stencil + true); // bind generates resource + + DoBindTexture( + GL_TEXTURE_RECTANGLE_ARB, client_texture_id_, kServiceTextureId); + + EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_RECTANGLE_ARB, + GL_TEXTURE_MIN_FILTER, + GL_NEAREST)); + EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_RECTANGLE_ARB, + GL_TEXTURE_MIN_FILTER, + GL_LINEAR)); + EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_RECTANGLE_ARB, + GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE)); + EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_RECTANGLE_ARB, + GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE)); + TexParameteri cmd; + cmd.Init(GL_TEXTURE_RECTANGLE_ARB, + GL_TEXTURE_MIN_FILTER, + GL_NEAREST); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + cmd.Init(GL_TEXTURE_RECTANGLE_ARB, + GL_TEXTURE_MIN_FILTER, + GL_LINEAR); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + cmd.Init(GL_TEXTURE_RECTANGLE_ARB, + GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + cmd.Init(GL_TEXTURE_RECTANGLE_ARB, + GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + TextureManager::TextureInfo* info = GetTextureInfo(client_texture_id_); + EXPECT_TRUE(info != NULL); + EXPECT_TRUE(info->target() == GL_TEXTURE_RECTANGLE_ARB); + EXPECT_TRUE(info->min_filter() == GL_LINEAR); + EXPECT_TRUE(info->wrap_s() == GL_CLAMP_TO_EDGE); + EXPECT_TRUE(info->wrap_t() == GL_CLAMP_TO_EDGE); +} + +TEST_F(GLES2DecoderManualInitTest, ARBTextureRectangleTextureParamInvalid) { + InitDecoder( + "GL_ARB_texture_rectangle", // extensions + false, // has alpha + false, // has depth + false, // has stencil + false, // request alpha + false, // request depth + false, // request stencil + true); // bind generates resource + + DoBindTexture( + GL_TEXTURE_RECTANGLE_ARB, client_texture_id_, kServiceTextureId); + + TexParameteri cmd; + cmd.Init(GL_TEXTURE_RECTANGLE_ARB, + GL_TEXTURE_MIN_FILTER, + GL_NEAREST_MIPMAP_NEAREST); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); + + cmd.Init(GL_TEXTURE_RECTANGLE_ARB, + GL_TEXTURE_WRAP_S, + GL_REPEAT); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); + + cmd.Init(GL_TEXTURE_RECTANGLE_ARB, + GL_TEXTURE_WRAP_T, + GL_REPEAT); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); + + TextureManager::TextureInfo* info = GetTextureInfo(client_texture_id_); + EXPECT_TRUE(info != NULL); + EXPECT_TRUE(info->target() == GL_TEXTURE_RECTANGLE_ARB); + EXPECT_TRUE(info->min_filter() == GL_LINEAR); + EXPECT_TRUE(info->wrap_s() == GL_CLAMP_TO_EDGE); + EXPECT_TRUE(info->wrap_t() == GL_CLAMP_TO_EDGE); +} + +TEST_F(GLES2DecoderManualInitTest, ARBTextureRectangleTexImage2DError) { + InitDecoder( + "GL_ARB_texture_rectangle", // extensions + false, // has alpha + false, // has depth + false, // has stencil + false, // request alpha + false, // request depth + false, // request stencil + true); // bind generates resource + + GLenum target = GL_TEXTURE_RECTANGLE_ARB; + GLint level = 0; + GLenum internal_format = GL_RGBA; + GLsizei width = 2; + GLsizei height = 4; + GLint border = 0; + GLenum format = GL_RGBA; + GLenum type = GL_UNSIGNED_BYTE; + DoBindTexture( + GL_TEXTURE_RECTANGLE_ARB, client_texture_id_, kServiceTextureId); + ASSERT_TRUE(GetTextureInfo(client_texture_id_) != NULL); + TexImage2D cmd; + cmd.Init(target, level, internal_format, width, height, border, format, + type, kSharedMemoryId, kSharedMemoryOffset); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + + // TexImage2D is not allowed with GL_TEXTURE_RECTANGLE_ARB targets. + EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); +} + TEST_F(GLES2DecoderTest, EnableFeatureCHROMIUMBadBucket) { const uint32 kBadBucketId = 123; EnableFeatureCHROMIUM cmd; diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h index c60e869..8cc7d9b 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h @@ -16,5 +16,6 @@ // TODO(gman): GetTranslatedShaderSourceANGLE // TODO(gman): PostSubBufferCHROMIUM +// TODO(gman): TexImageIOSurface2DCHROMIUM #endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_ 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 70c269d..9010fb9 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc @@ -121,6 +121,13 @@ void GLES2DecoderTestBase::InitDecoder( .Times(1) .RetiresOnSaturation(); } + if (group_->feature_info()->feature_flags().arb_texture_rectangle) { + EXPECT_CALL(*gl_, BindTexture( + GL_TEXTURE_RECTANGLE_ARB, + TestHelper::kServiceDefaultRectangleTextureId)) + .Times(1) + .RetiresOnSaturation(); + } EXPECT_CALL(*gl_, BindTexture( GL_TEXTURE_CUBE_MAP, TestHelper::kServiceDefaultTextureCubemapId)) .Times(1) diff --git a/gpu/command_buffer/service/test_helper.cc b/gpu/command_buffer/service/test_helper.cc index 7f712fe..0290980 100644 --- a/gpu/command_buffer/service/test_helper.cc +++ b/gpu/command_buffer/service/test_helper.cc @@ -29,11 +29,13 @@ namespace gles2 { // GCC requires these declarations, but MSVC requires they not be present #ifndef COMPILER_MSVC const GLuint TestHelper::kServiceBlackTexture2dId; -const GLuint TestHelper::kServiceBlackTextureCubemapId; const GLuint TestHelper::kServiceDefaultTexture2dId; +const GLuint TestHelper::kServiceBlackTextureCubemapId; const GLuint TestHelper::kServiceDefaultTextureCubemapId; -const GLuint TestHelper::kServiceDefaultExternalTextureId; const GLuint TestHelper::kServiceBlackExternalTextureId; +const GLuint TestHelper::kServiceDefaultExternalTextureId; +const GLuint TestHelper::kServiceBlackRectangleTextureId; +const GLuint TestHelper::kServiceDefaultRectangleTextureId; const GLint TestHelper::kMaxSamples; const GLint TestHelper::kMaxRenderbufferSize; @@ -51,74 +53,110 @@ const GLint TestHelper::kMaxVertexUniformVectors; const GLint TestHelper::kMaxVertexUniformComponents; #endif -void TestHelper::SetupTextureManagerInitExpectations( - ::gfx::MockGLInterface* gl, - const char* extensions) { - static GLuint texture_ids[] = { +void TestHelper::SetupTextureInitializationExpectations( + ::gfx::MockGLInterface* gl, GLenum target) { + InSequence sequence; + + bool needs_initialization = (target != GL_TEXTURE_EXTERNAL_OES); + bool needs_faces = (target == GL_TEXTURE_CUBE_MAP); + + static GLuint texture_2d_ids[] = { kServiceBlackTexture2dId, - kServiceDefaultTexture2dId, + kServiceDefaultTexture2dId }; + static GLuint texture_cube_map_ids[] = { kServiceBlackTextureCubemapId, - kServiceDefaultTextureCubemapId, - }; - EXPECT_CALL(*gl, GenTextures(arraysize(texture_ids), _)) + kServiceDefaultTextureCubemapId }; + static GLuint texture_external_oes_ids[] = { + kServiceBlackExternalTextureId, + kServiceDefaultExternalTextureId }; + static GLuint texture_rectangle_arb_ids[] = { + kServiceBlackRectangleTextureId, + kServiceDefaultRectangleTextureId }; + + const GLuint* texture_ids = NULL; + switch (target) { + case GL_TEXTURE_2D: + texture_ids = &texture_2d_ids[0]; + break; + case GL_TEXTURE_CUBE_MAP: + texture_ids = &texture_cube_map_ids[0]; + break; + case GL_TEXTURE_EXTERNAL_OES: + texture_ids = &texture_external_oes_ids[0]; + break; + case GL_TEXTURE_RECTANGLE_ARB: + texture_ids = &texture_rectangle_arb_ids[0]; + break; + default: + NOTREACHED(); + } + + int array_size = 2; + + EXPECT_CALL(*gl, GenTextures(array_size, _)) .WillOnce(SetArrayArgument<1>(texture_ids, - texture_ids + arraysize(texture_ids))) - .RetiresOnSaturation(); - for (int ii = 0; ii < 2; ++ii) { - EXPECT_CALL(*gl, BindTexture(GL_TEXTURE_2D, texture_ids[ii])) - .Times(1) - .RetiresOnSaturation(); - EXPECT_CALL(*gl, TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, - GL_UNSIGNED_BYTE, _)) - .Times(1) - .RetiresOnSaturation(); - EXPECT_CALL(*gl, BindTexture(GL_TEXTURE_CUBE_MAP, texture_ids[2 + ii])) + texture_ids + array_size)) + .RetiresOnSaturation(); + for (int ii = 0; ii < array_size; ++ii) { + EXPECT_CALL(*gl, BindTexture(target, texture_ids[ii])) .Times(1) .RetiresOnSaturation(); - static GLenum faces[] = { - GL_TEXTURE_CUBE_MAP_POSITIVE_X, - GL_TEXTURE_CUBE_MAP_NEGATIVE_X, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - GL_TEXTURE_CUBE_MAP_POSITIVE_Z, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, - }; - for (size_t ii = 0; ii < arraysize(faces); ++ii) { - EXPECT_CALL(*gl, TexImage2D(faces[ii], 0, GL_RGBA, 1, 1, 0, GL_RGBA, - GL_UNSIGNED_BYTE, _)) - .Times(1) - .RetiresOnSaturation(); + if (needs_initialization) { + if (needs_faces) { + static GLenum faces[] = { + GL_TEXTURE_CUBE_MAP_POSITIVE_X, + GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, + }; + for (size_t ii = 0; ii < arraysize(faces); ++ii) { + EXPECT_CALL(*gl, TexImage2D(faces[ii], 0, GL_RGBA, 1, 1, 0, GL_RGBA, + GL_UNSIGNED_BYTE, _)) + .Times(1) + .RetiresOnSaturation(); + } + } else { + EXPECT_CALL(*gl, TexImage2D(target, 0, GL_RGBA, 1, 1, 0, GL_RGBA, + GL_UNSIGNED_BYTE, _)) + .Times(1) + .RetiresOnSaturation(); + } } } - EXPECT_CALL(*gl, BindTexture(GL_TEXTURE_2D, 0)) - .Times(1) - .RetiresOnSaturation(); - EXPECT_CALL(*gl, BindTexture(GL_TEXTURE_CUBE_MAP, 0)) + EXPECT_CALL(*gl, BindTexture(target, 0)) .Times(1) .RetiresOnSaturation(); +} + +void TestHelper::SetupTextureManagerInitExpectations( + ::gfx::MockGLInterface* gl, + const char* extensions) { + InSequence sequence; + + SetupTextureInitializationExpectations(gl, GL_TEXTURE_2D); + SetupTextureInitializationExpectations(gl, GL_TEXTURE_CUBE_MAP); bool ext_image_external = false; + bool arb_texture_rectangle = false; CStringTokenizer t(extensions, extensions + strlen(extensions), " "); while (t.GetNext()) { if (t.token() == "GL_OES_EGL_image_external") { ext_image_external = true; break; } + if (t.token() == "GL_ARB_texture_rectangle") { + arb_texture_rectangle = true; + break; + } } if (ext_image_external) { - static GLuint external_texture_ids[] = { - kServiceDefaultExternalTextureId, - kServiceBlackExternalTextureId, - }; - EXPECT_CALL(*gl, GenTextures(arraysize(external_texture_ids), _)) - .WillOnce(SetArrayArgument<1>( - external_texture_ids, - external_texture_ids + arraysize(external_texture_ids))) - .RetiresOnSaturation(); - EXPECT_CALL(*gl, BindTexture(GL_TEXTURE_EXTERNAL_OES, 0)) - .Times(1) - .RetiresOnSaturation(); + SetupTextureInitializationExpectations(gl, GL_TEXTURE_EXTERNAL_OES); + } + if (arb_texture_rectangle) { + SetupTextureInitializationExpectations(gl, GL_TEXTURE_RECTANGLE_ARB); } } diff --git a/gpu/command_buffer/service/test_helper.h b/gpu/command_buffer/service/test_helper.h index 6c6dcd0..ec563315 100644 --- a/gpu/command_buffer/service/test_helper.h +++ b/gpu/command_buffer/service/test_helper.h @@ -15,11 +15,13 @@ struct DisallowedFeatures; class TestHelper { public: static const GLuint kServiceBlackTexture2dId = 701; - static const GLuint kServiceBlackTextureCubemapId = 702; - static const GLuint kServiceDefaultTexture2dId = 703; + static const GLuint kServiceDefaultTexture2dId = 702; + static const GLuint kServiceBlackTextureCubemapId = 703; static const GLuint kServiceDefaultTextureCubemapId = 704; - static const GLuint kServiceDefaultExternalTextureId = 705; - static const GLuint kServiceBlackExternalTextureId = 706; + static const GLuint kServiceBlackExternalTextureId = 705; + static const GLuint kServiceDefaultExternalTextureId = 706; + static const GLuint kServiceBlackRectangleTextureId = 707; + static const GLuint kServiceDefaultRectangleTextureId = 708; static const GLint kMaxSamples = 4; static const GLint kMaxRenderbufferSize = 1024; @@ -45,6 +47,9 @@ class TestHelper { ::gfx::MockGLInterface* gl, const char* extensions); static void SetupTextureManagerInitExpectations(::gfx::MockGLInterface* gl, const char* extensions); + private: + static void SetupTextureInitializationExpectations(::gfx::MockGLInterface* gl, + GLenum target); }; } // namespace gles2 diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc index 3a433d3..db0825c 100644 --- a/gpu/command_buffer/service/texture_manager.cc +++ b/gpu/command_buffer/service/texture_manager.cc @@ -20,6 +20,7 @@ static size_t GLTargetToFaceIndex(GLenum target) { switch (target) { case GL_TEXTURE_2D: case GL_TEXTURE_EXTERNAL_OES: + case GL_TEXTURE_RECTANGLE_ARB: return 0; case GL_TEXTURE_CUBE_MAP_POSITIVE_X: return 0; @@ -92,7 +93,8 @@ bool TextureManager::TextureInfo::CanRender( return false; } bool needs_mips = NeedsMips(); - if (npot() && !feature_info->feature_flags().npot_ok) { + if ((npot() && !feature_info->feature_flags().npot_ok) || + (target_ == GL_TEXTURE_RECTANGLE_ARB)) { return !needs_mips && wrap_s_ == GL_CLAMP_TO_EDGE && wrap_t_ == GL_CLAMP_TO_EDGE; @@ -151,7 +153,7 @@ void TextureManager::TextureInfo::SetTarget(GLenum target, GLint max_levels) { level_infos_[ii].resize(max_levels); } - if (target == GL_TEXTURE_EXTERNAL_OES) { + if (target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_RECTANGLE_ARB) { min_filter_ = GL_LINEAR; wrap_s_ = wrap_t_ = GL_CLAMP_TO_EDGE; } @@ -161,7 +163,8 @@ bool TextureManager::TextureInfo::CanGenerateMipmaps( const FeatureInfo* feature_info) const { if ((npot() && !feature_info->feature_flags().npot_ok) || level_infos_.empty() || - target_ == GL_TEXTURE_EXTERNAL_OES) { + target_ == GL_TEXTURE_EXTERNAL_OES || + target_ == GL_TEXTURE_RECTANGLE_ARB) { return false; } const TextureInfo::LevelInfo& first = level_infos_[0][0]; @@ -327,7 +330,8 @@ bool TextureManager::TextureInfo::SetParameter( const FeatureInfo* feature_info, GLenum pname, GLint param) { DCHECK(feature_info); - if (target_ == GL_TEXTURE_EXTERNAL_OES) { + if (target_ == GL_TEXTURE_EXTERNAL_OES || + target_ == GL_TEXTURE_RECTANGLE_ARB) { if (pname == GL_TEXTURE_MIN_FILTER && (param != GL_NEAREST && param != GL_LINEAR)) return false; @@ -540,7 +544,9 @@ TextureManager::TextureManager( num_unsafe_textures_(0), num_uncleared_mips_(0), black_2d_texture_id_(0), - black_cube_texture_id_(0) { + black_cube_texture_id_(0), + black_oes_external_texture_id_(0), + black_arb_texture_rectangle_id_(0) { } bool TextureManager::Initialize(const FeatureInfo* feature_info) { @@ -549,65 +555,86 @@ bool TextureManager::Initialize(const FeatureInfo* feature_info) { // resources and all contexts that share resource share the same default // texture. + default_texture_2d_ = CreateDefaultAndBlackTextures( + feature_info, GL_TEXTURE_2D, &black_2d_texture_id_); + default_texture_cube_map_ = CreateDefaultAndBlackTextures( + feature_info, GL_TEXTURE_CUBE_MAP, &black_cube_texture_id_); + + if (feature_info->feature_flags().oes_egl_image_external) { + default_texture_external_oes_ = CreateDefaultAndBlackTextures( + feature_info, GL_TEXTURE_EXTERNAL_OES, + &black_oes_external_texture_id_); + } + + if (feature_info->feature_flags().arb_texture_rectangle) { + default_texture_rectangle_arb_ = CreateDefaultAndBlackTextures( + feature_info, GL_TEXTURE_RECTANGLE_ARB, + &black_arb_texture_rectangle_id_); + } + + return true; +} + +TextureManager::TextureInfo::Ref TextureManager::CreateDefaultAndBlackTextures( + const FeatureInfo* feature_info, + GLenum target, + GLuint* black_texture) { + static uint8 black[] = {0, 0, 0, 255}; + + // Sampling a texture not associated with any EGLImage sibling will return + // black values according to the spec. + bool needs_initialization = (target != GL_TEXTURE_EXTERNAL_OES); + bool needs_faces = (target == GL_TEXTURE_CUBE_MAP); + // Make default textures and texture for replacing non-renderable textures. - GLuint ids[4]; + GLuint ids[2]; glGenTextures(arraysize(ids), ids); - static uint8 black[] = {0, 0, 0, 255}; - for (int ii = 0; ii < 2; ++ii) { - glBindTexture(GL_TEXTURE_2D, ids[ii]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, - GL_UNSIGNED_BYTE, black); - glBindTexture(GL_TEXTURE_CUBE_MAP, ids[2 + ii]); - for (int ii = 0; ii < GLES2Util::kNumFaces; ++ii) { - glTexImage2D(GLES2Util::IndexToGLFaceTarget(ii), 0, GL_RGBA, 1, 1, 0, - GL_RGBA, GL_UNSIGNED_BYTE, black); + for (unsigned long ii = 0; ii < arraysize(ids); ++ii) { + glBindTexture(target, ids[ii]); + if (needs_initialization) { + if (needs_faces) { + for (int jj = 0; jj < GLES2Util::kNumFaces; ++jj) { + glTexImage2D(GLES2Util::IndexToGLFaceTarget(jj), 0, GL_RGBA, 1, 1, 0, + GL_RGBA, GL_UNSIGNED_BYTE, black); + } + } else { + glTexImage2D(target, 0, GL_RGBA, 1, 1, 0, GL_RGBA, + GL_UNSIGNED_BYTE, black); + } } } - glBindTexture(GL_TEXTURE_2D, 0); - glBindTexture(GL_TEXTURE_CUBE_MAP, 0); + glBindTexture(target, 0); // Since we are manually setting up these textures // we need to manually manipulate some of the their bookkeeping. - num_unrenderable_textures_ += 2; + ++num_unrenderable_textures_; + TextureInfo::Ref default_texture = TextureInfo::Ref(new TextureInfo(ids[1])); + SetInfoTarget(feature_info, default_texture, target); FeatureInfo temp_feature_info; - default_texture_2d_ = TextureInfo::Ref(new TextureInfo(ids[1])); - SetInfoTarget(feature_info, default_texture_2d_, GL_TEXTURE_2D); - SetLevelInfo(&temp_feature_info, default_texture_2d_, - GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true); - default_texture_cube_map_ = TextureInfo::Ref(new TextureInfo(ids[3])); - SetInfoTarget(feature_info, default_texture_cube_map_, GL_TEXTURE_CUBE_MAP); - for (int ii = 0; ii < GLES2Util::kNumFaces; ++ii) { - SetLevelInfo( - &temp_feature_info, default_texture_cube_map_, - GLES2Util::IndexToGLFaceTarget(ii), - 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true); - } - - black_2d_texture_id_ = ids[0]; - black_cube_texture_id_ = ids[2]; - - if (feature_info->feature_flags().oes_egl_image_external) { - // Since we are manually setting up these textures - // we need to manually manipulate some of the their bookkeeping. - num_unrenderable_textures_ += 1; - GLuint external_ids[2]; - glGenTextures(arraysize(external_ids), external_ids); - glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0); - default_texture_external_oes_ = TextureInfo::Ref( - new TextureInfo(external_ids[0])); - SetInfoTarget(feature_info, - default_texture_external_oes_, - GL_TEXTURE_EXTERNAL_OES); - default_texture_external_oes_->SetLevelInfo( - &temp_feature_info, GL_TEXTURE_EXTERNAL_OES, 0, - GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true); - - // Sampling a texture not associated with any EGLImage sibling will return - // black values according to the spec. - black_oes_external_texture_id_ = external_ids[1]; + if (needs_faces) { + for (int ii = 0; ii < GLES2Util::kNumFaces; ++ii) { + SetLevelInfo( + &temp_feature_info, default_texture, + GLES2Util::IndexToGLFaceTarget(ii), + 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true); + } + } else { + // TODO(kbr): previous code called SetLevelInfo directly on the + // TextureInfo object for the GL_TEXTURE_EXTERNAL_OES case. + // Unclear whether this was deliberate. + if (needs_initialization) { + SetLevelInfo(&temp_feature_info, default_texture, + GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, + GL_RGBA, GL_UNSIGNED_BYTE, true); + } else { + default_texture->SetLevelInfo( + &temp_feature_info, GL_TEXTURE_EXTERNAL_OES, 0, + GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true); + } } - return true; + *black_texture = ids[0]; + return default_texture; } bool TextureManager::ValidForTarget( diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h index 0fccbf6..aaeed80 100644 --- a/gpu/command_buffer/service/texture_manager.h +++ b/gpu/command_buffer/service/texture_manager.h @@ -253,7 +253,7 @@ class TextureManager { // Sets the TextureInfo's target // Parameters: // target: GL_TEXTURE_2D or GL_TEXTURE_CUBE_MAP or - // GL_TEXTURE_EXTERNAL_OES + // GL_TEXTURE_EXTERNAL_OES or GL_TEXTURE_RECTANGLE_ARB // max_levels: The maximum levels this type of target can have. void SetTarget(GLenum target, GLint max_levels); @@ -415,6 +415,8 @@ class TextureManager { return default_texture_cube_map_; case GL_TEXTURE_EXTERNAL_OES: return default_texture_external_oes_; + case GL_TEXTURE_RECTANGLE_ARB: + return default_texture_rectangle_arb_; default: NOTREACHED(); return NULL; @@ -441,6 +443,8 @@ class TextureManager { return black_cube_texture_id_; case GL_SAMPLER_EXTERNAL_OES: return black_oes_external_texture_id_; + case GL_SAMPLER_2D_RECT_ARB: + return black_arb_texture_rectangle_id_; default: NOTREACHED(); return 0; @@ -448,6 +452,12 @@ class TextureManager { } private: + // Helper for Initialize(). + TextureInfo::Ref CreateDefaultAndBlackTextures( + const FeatureInfo* feature_info, + GLenum target, + GLuint* black_texture); + // Info for each texture in the system. typedef base::hash_map<GLuint, TextureInfo::Ref> TextureInfoMap; TextureInfoMap texture_infos_; @@ -467,11 +477,13 @@ class TextureManager { GLuint black_2d_texture_id_; GLuint black_cube_texture_id_; GLuint black_oes_external_texture_id_; + GLuint black_arb_texture_rectangle_id_; // The default textures for each target (texture name = 0) TextureInfo::Ref default_texture_2d_; TextureInfo::Ref default_texture_cube_map_; TextureInfo::Ref default_texture_external_oes_; + TextureInfo::Ref default_texture_rectangle_arb_; DISALLOW_COPY_AND_ASSIGN(TextureManager); }; diff --git a/gpu/command_buffer/service/texture_manager_unittest.cc b/gpu/command_buffer/service/texture_manager_unittest.cc index 15fc02e..4481567 100644 --- a/gpu/command_buffer/service/texture_manager_unittest.cc +++ b/gpu/command_buffer/service/texture_manager_unittest.cc @@ -27,12 +27,6 @@ class TextureManagerTest : public testing::Test { static const GLint kMaxCubeMapLevels = 4; static const GLint kMaxExternalLevels = 1; - static const GLuint kServiceBlackTexture2dId = 701; - static const GLuint kServiceBlackTextureCubemapId = 702; - static const GLuint kServiceDefaultTexture2dId = 703; - static const GLuint kServiceDefaultTextureCubemapId = 704; - - TextureManagerTest() : manager_(kMaxTextureSize, kMaxCubeMapTextureSize) { } @@ -69,10 +63,6 @@ const GLint TextureManagerTest::kMaxExternalTextureSize; const GLint TextureManagerTest::kMax2dLevels; const GLint TextureManagerTest::kMaxCubeMapLevels; const GLint TextureManagerTest::kMaxExternalLevels; -const GLuint TextureManagerTest::kServiceBlackTexture2dId; -const GLuint TextureManagerTest::kServiceBlackTextureCubemapId; -const GLuint TextureManagerTest::kServiceDefaultTexture2dId; -const GLuint TextureManagerTest::kServiceDefaultTextureCubemapId; #endif TEST_F(TextureManagerTest, Basic) { |