diff options
Diffstat (limited to 'gpu/command_buffer')
46 files changed, 4881 insertions, 51 deletions
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py index dd6a050..09cdc7b 100755 --- a/gpu/command_buffer/build_gles2_cmd_buffer.py +++ b/gpu/command_buffer/build_gles2_cmd_buffer.py @@ -540,6 +540,31 @@ _STATES = { }, ], }, + 'PathStencilFuncCHROMIUM': { + 'type': 'Normal', + 'func': 'PathStencilFuncNV', + 'extension_flag': 'chromium_path_rendering', + 'states': [ + { + 'name': 'stencil_path_func', + 'type': 'GLenum', + 'enum': 'GL_PATH_STENCIL_FUNC_CHROMIUM', + 'default': 'GL_ALWAYS', + }, + { + 'name': 'stencil_path_ref', + 'type': 'GLint', + 'enum': 'GL_PATH_STENCIL_REF_CHROMIUM', + 'default': '0', + }, + { + 'name': 'stencil_path_mask', + 'type': 'GLuint', + 'enum': 'GL_PATH_STENCIL_VALUE_MASK_CHROMIUM', + 'default': '0xFFFFFFFFU', + }, + ], + }, } # Named type info object represents a named type that is used in OpenGL call @@ -1479,6 +1504,57 @@ _NAMED_TYPE_INFO = { 'GL_UNSIGNED_BYTE_3_3_2', ], }, + 'PathCoordType': { + 'type': 'GLenum', + 'valid': [ + 'GL_BYTE', + 'GL_UNSIGNED_BYTE', + 'GL_SHORT', + 'GL_UNSIGNED_SHORT', + 'GL_FLOAT', + ], + }, + 'PathCoverMode': { + 'type': 'GLenum', + 'valid': [ + 'GL_CONVEX_HULL_CHROMIUM', + 'GL_BOUNDING_BOX_CHROMIUM', + ], + }, + 'PathFillMode': { + 'type': 'GLenum', + 'valid': [ + 'GL_INVERT', + 'GL_COUNT_UP_CHROMIUM', + 'GL_COUNT_DOWN_CHROMIUM', + ], + }, + 'PathParameter': { + 'type': 'GLenum', + 'valid': [ + 'GL_PATH_STROKE_WIDTH_CHROMIUM', + 'GL_PATH_END_CAPS_CHROMIUM', + 'GL_PATH_JOIN_STYLE_CHROMIUM', + 'GL_PATH_MITER_LIMIT_CHROMIUM', + 'GL_PATH_STROKE_BOUND_CHROMIUM', + ] + }, + 'PathParameterCapValues': { + 'type': 'GLint', + 'valid': [ + 'GL_FLAT', + 'GL_SQUARE_CHROMIUM', + 'GL_ROUND_CHROMIUM', + ] + }, + 'PathParameterJoinValues': { + 'type': 'GLint', + 'valid': [ + 'GL_MITER_REVERT_CHROMIUM', + 'GL_BEVEL_CHROMIUM', + 'GL_ROUND_CHROMIUM', + ] + }, 'ReadPixelType': { 'type': 'GLenum', 'valid': [ @@ -3969,6 +4045,94 @@ _FUNCTION_INFO = { 'extension': True, 'extension_flag': 'chromium_path_rendering', }, + 'GenPathsCHROMIUM': { + 'type': 'Custom', + 'cmd_args': 'GLuint first_client_id, GLsizei range', + 'chromium': True, + 'extension': True, + 'extension_flag': 'chromium_path_rendering', + }, + 'DeletePathsCHROMIUM': { + 'type': 'Custom', + 'cmd_args': 'GLuint first_client_id, GLsizei range', + 'impl_func': False, + 'unit_test': False, + 'chromium': True, + 'extension': True, + 'extension_flag': 'chromium_path_rendering', + }, + 'IsPathCHROMIUM': { + 'type': 'Is', + 'decoder_func': 'DoIsPathCHROMIUM', + 'gl_test_func': 'glIsPathNV', + 'chromium': True, + 'extension': True, + 'extension_flag': 'chromium_path_rendering', + }, + 'PathCommandsCHROMIUM': { + 'type': 'Manual', + 'immediate': False, + 'chromium': True, + 'extension': True, + 'extension_flag': 'chromium_path_rendering', + }, + 'PathParameterfCHROMIUM': { + 'type': 'Custom', + 'chromium': True, + 'extension': True, + 'extension_flag': 'chromium_path_rendering', + }, + 'PathParameteriCHROMIUM': { + 'type': 'Custom', + 'chromium': True, + 'extension': True, + 'extension_flag': 'chromium_path_rendering', + }, + 'PathStencilFuncCHROMIUM': { + 'type': 'StateSet', + 'state': 'PathStencilFuncCHROMIUM', + 'decoder_func': 'glPathStencilFuncNV', + 'chromium': True, + 'extension': True, + 'extension_flag': 'chromium_path_rendering', + }, + 'StencilFillPathCHROMIUM': { + 'type': 'Custom', + 'chromium': True, + 'extension': True, + 'extension_flag': 'chromium_path_rendering', + }, + 'StencilStrokePathCHROMIUM': { + 'type': 'Custom', + 'chromium': True, + 'extension': True, + 'extension_flag': 'chromium_path_rendering', + }, + 'CoverFillPathCHROMIUM': { + 'type': 'Custom', + 'chromium': True, + 'extension': True, + 'extension_flag': 'chromium_path_rendering', + }, + 'CoverStrokePathCHROMIUM': { + 'type': 'Custom', + 'chromium': True, + 'extension': True, + 'extension_flag': 'chromium_path_rendering', + }, + 'StencilThenCoverFillPathCHROMIUM': { + 'type': 'Custom', + 'chromium': True, + 'extension': True, + 'extension_flag': 'chromium_path_rendering', + }, + 'StencilThenCoverStrokePathCHROMIUM': { + 'type': 'Custom', + 'chromium': True, + 'extension': True, + 'extension_flag': 'chromium_path_rendering', + }, + } @@ -7939,6 +8103,7 @@ TEST_P(%(test_name)s, %(name)sInvalidArgsBadSharedMemoryId) { def WriteServiceImplementation(self, func, file): """Overrriden from TypeHandler.""" self.WriteServiceHandlerFunctionHeader(func, file) + self.WriteHandlerExtensionCheck(func, file) args = func.GetOriginalArgs() for arg in args: arg.WriteGetCode(file) diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h index 4f96672a..4e304c1 100644 --- a/gpu/command_buffer/client/gles2_c_lib_autogen.h +++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h @@ -1410,6 +1410,59 @@ void GLES2MatrixLoadfCHROMIUM(GLenum matrixMode, const GLfloat* m) { void GLES2MatrixLoadIdentityCHROMIUM(GLenum matrixMode) { gles2::GetGLContext()->MatrixLoadIdentityCHROMIUM(matrixMode); } +GLuint GLES2GenPathsCHROMIUM(GLsizei range) { + return gles2::GetGLContext()->GenPathsCHROMIUM(range); +} +void GLES2DeletePathsCHROMIUM(GLuint path, GLsizei range) { + gles2::GetGLContext()->DeletePathsCHROMIUM(path, range); +} +GLboolean GLES2IsPathCHROMIUM(GLuint path) { + return gles2::GetGLContext()->IsPathCHROMIUM(path); +} +void GLES2PathCommandsCHROMIUM(GLuint path, + GLsizei numCommands, + const GLubyte* commands, + GLsizei numCoords, + GLenum coordType, + const GLvoid* coords) { + gles2::GetGLContext()->PathCommandsCHROMIUM(path, numCommands, commands, + numCoords, coordType, coords); +} +void GLES2PathParameterfCHROMIUM(GLuint path, GLenum pname, GLfloat value) { + gles2::GetGLContext()->PathParameterfCHROMIUM(path, pname, value); +} +void GLES2PathParameteriCHROMIUM(GLuint path, GLenum pname, GLint value) { + gles2::GetGLContext()->PathParameteriCHROMIUM(path, pname, value); +} +void GLES2PathStencilFuncCHROMIUM(GLenum func, GLint ref, GLuint mask) { + gles2::GetGLContext()->PathStencilFuncCHROMIUM(func, ref, mask); +} +void GLES2StencilFillPathCHROMIUM(GLuint path, GLenum fillMode, GLuint mask) { + gles2::GetGLContext()->StencilFillPathCHROMIUM(path, fillMode, mask); +} +void GLES2StencilStrokePathCHROMIUM(GLuint path, GLint reference, GLuint mask) { + gles2::GetGLContext()->StencilStrokePathCHROMIUM(path, reference, mask); +} +void GLES2CoverFillPathCHROMIUM(GLuint path, GLenum coverMode) { + gles2::GetGLContext()->CoverFillPathCHROMIUM(path, coverMode); +} +void GLES2CoverStrokePathCHROMIUM(GLuint path, GLenum coverMode) { + gles2::GetGLContext()->CoverStrokePathCHROMIUM(path, coverMode); +} +void GLES2StencilThenCoverFillPathCHROMIUM(GLuint path, + GLenum fillMode, + GLuint mask, + GLenum coverMode) { + gles2::GetGLContext()->StencilThenCoverFillPathCHROMIUM(path, fillMode, mask, + coverMode); +} +void GLES2StencilThenCoverStrokePathCHROMIUM(GLuint path, + GLint reference, + GLuint mask, + GLenum coverMode) { + gles2::GetGLContext()->StencilThenCoverStrokePathCHROMIUM(path, reference, + mask, coverMode); +} GLenum GLES2GetGraphicsResetStatusKHR() { return gles2::GetGLContext()->GetGraphicsResetStatusKHR(); } @@ -2648,6 +2701,59 @@ extern const NameToFunc g_gles2_function_table[] = { reinterpret_cast<GLES2FunctionPointer>(glMatrixLoadIdentityCHROMIUM), }, { + "glGenPathsCHROMIUM", + reinterpret_cast<GLES2FunctionPointer>(glGenPathsCHROMIUM), + }, + { + "glDeletePathsCHROMIUM", + reinterpret_cast<GLES2FunctionPointer>(glDeletePathsCHROMIUM), + }, + { + "glIsPathCHROMIUM", + reinterpret_cast<GLES2FunctionPointer>(glIsPathCHROMIUM), + }, + { + "glPathCommandsCHROMIUM", + reinterpret_cast<GLES2FunctionPointer>(glPathCommandsCHROMIUM), + }, + { + "glPathParameterfCHROMIUM", + reinterpret_cast<GLES2FunctionPointer>(glPathParameterfCHROMIUM), + }, + { + "glPathParameteriCHROMIUM", + reinterpret_cast<GLES2FunctionPointer>(glPathParameteriCHROMIUM), + }, + { + "glPathStencilFuncCHROMIUM", + reinterpret_cast<GLES2FunctionPointer>(glPathStencilFuncCHROMIUM), + }, + { + "glStencilFillPathCHROMIUM", + reinterpret_cast<GLES2FunctionPointer>(glStencilFillPathCHROMIUM), + }, + { + "glStencilStrokePathCHROMIUM", + reinterpret_cast<GLES2FunctionPointer>(glStencilStrokePathCHROMIUM), + }, + { + "glCoverFillPathCHROMIUM", + reinterpret_cast<GLES2FunctionPointer>(glCoverFillPathCHROMIUM), + }, + { + "glCoverStrokePathCHROMIUM", + reinterpret_cast<GLES2FunctionPointer>(glCoverStrokePathCHROMIUM), + }, + { + "glStencilThenCoverFillPathCHROMIUM", + reinterpret_cast<GLES2FunctionPointer>(glStencilThenCoverFillPathCHROMIUM), + }, + { + "glStencilThenCoverStrokePathCHROMIUM", + reinterpret_cast<GLES2FunctionPointer>( + glStencilThenCoverStrokePathCHROMIUM), + }, + { "glGetGraphicsResetStatusKHR", reinterpret_cast<GLES2FunctionPointer>(glGetGraphicsResetStatusKHR), }, diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h index ce32148..abf4902 100644 --- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h +++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h @@ -2833,6 +2833,125 @@ void MatrixLoadIdentityCHROMIUM(GLenum matrixMode) { } } +void GenPathsCHROMIUM(GLuint first_client_id, GLsizei range) { + gles2::cmds::GenPathsCHROMIUM* c = + GetCmdSpace<gles2::cmds::GenPathsCHROMIUM>(); + if (c) { + c->Init(first_client_id, range); + } +} + +void DeletePathsCHROMIUM(GLuint first_client_id, GLsizei range) { + gles2::cmds::DeletePathsCHROMIUM* c = + GetCmdSpace<gles2::cmds::DeletePathsCHROMIUM>(); + if (c) { + c->Init(first_client_id, range); + } +} + +void IsPathCHROMIUM(GLuint path, + uint32_t result_shm_id, + uint32_t result_shm_offset) { + gles2::cmds::IsPathCHROMIUM* c = GetCmdSpace<gles2::cmds::IsPathCHROMIUM>(); + if (c) { + c->Init(path, result_shm_id, result_shm_offset); + } +} + +void PathCommandsCHROMIUM(GLuint path, + GLsizei numCommands, + uint32_t commands_shm_id, + uint32_t commands_shm_offset, + GLsizei numCoords, + GLenum coordType, + uint32_t coords_shm_id, + uint32_t coords_shm_offset) { + gles2::cmds::PathCommandsCHROMIUM* c = + GetCmdSpace<gles2::cmds::PathCommandsCHROMIUM>(); + if (c) { + c->Init(path, numCommands, commands_shm_id, commands_shm_offset, numCoords, + coordType, coords_shm_id, coords_shm_offset); + } +} + +void PathParameterfCHROMIUM(GLuint path, GLenum pname, GLfloat value) { + gles2::cmds::PathParameterfCHROMIUM* c = + GetCmdSpace<gles2::cmds::PathParameterfCHROMIUM>(); + if (c) { + c->Init(path, pname, value); + } +} + +void PathParameteriCHROMIUM(GLuint path, GLenum pname, GLint value) { + gles2::cmds::PathParameteriCHROMIUM* c = + GetCmdSpace<gles2::cmds::PathParameteriCHROMIUM>(); + if (c) { + c->Init(path, pname, value); + } +} + +void PathStencilFuncCHROMIUM(GLenum func, GLint ref, GLuint mask) { + gles2::cmds::PathStencilFuncCHROMIUM* c = + GetCmdSpace<gles2::cmds::PathStencilFuncCHROMIUM>(); + if (c) { + c->Init(func, ref, mask); + } +} + +void StencilFillPathCHROMIUM(GLuint path, GLenum fillMode, GLuint mask) { + gles2::cmds::StencilFillPathCHROMIUM* c = + GetCmdSpace<gles2::cmds::StencilFillPathCHROMIUM>(); + if (c) { + c->Init(path, fillMode, mask); + } +} + +void StencilStrokePathCHROMIUM(GLuint path, GLint reference, GLuint mask) { + gles2::cmds::StencilStrokePathCHROMIUM* c = + GetCmdSpace<gles2::cmds::StencilStrokePathCHROMIUM>(); + if (c) { + c->Init(path, reference, mask); + } +} + +void CoverFillPathCHROMIUM(GLuint path, GLenum coverMode) { + gles2::cmds::CoverFillPathCHROMIUM* c = + GetCmdSpace<gles2::cmds::CoverFillPathCHROMIUM>(); + if (c) { + c->Init(path, coverMode); + } +} + +void CoverStrokePathCHROMIUM(GLuint path, GLenum coverMode) { + gles2::cmds::CoverStrokePathCHROMIUM* c = + GetCmdSpace<gles2::cmds::CoverStrokePathCHROMIUM>(); + if (c) { + c->Init(path, coverMode); + } +} + +void StencilThenCoverFillPathCHROMIUM(GLuint path, + GLenum fillMode, + GLuint mask, + GLenum coverMode) { + gles2::cmds::StencilThenCoverFillPathCHROMIUM* c = + GetCmdSpace<gles2::cmds::StencilThenCoverFillPathCHROMIUM>(); + if (c) { + c->Init(path, fillMode, mask, coverMode); + } +} + +void StencilThenCoverStrokePathCHROMIUM(GLuint path, + GLint reference, + GLuint mask, + GLenum coverMode) { + gles2::cmds::StencilThenCoverStrokePathCHROMIUM* c = + GetCmdSpace<gles2::cmds::StencilThenCoverStrokePathCHROMIUM>(); + if (c) { + c->Init(path, reference, mask, coverMode); + } +} + void BlendBarrierKHR() { gles2::cmds::BlendBarrierKHR* c = GetCmdSpace<gles2::cmds::BlendBarrierKHR>(); if (c) { diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc index 5cc28ddc..5dcc9dd 100644 --- a/gpu/command_buffer/client/gles2_implementation.cc +++ b/gpu/command_buffer/client/gles2_implementation.cc @@ -255,6 +255,11 @@ IdHandlerInterface* GLES2Implementation::GetIdHandler(int namespace_id) const { return share_group_->GetIdHandler(namespace_id); } +RangeIdHandlerInterface* GLES2Implementation::GetRangeIdHandler( + int namespace_id) const { + return share_group_->GetRangeIdHandler(namespace_id); +} + IdAllocator* GLES2Implementation::GetIdAllocator(int namespace_id) const { if (namespace_id == id_namespaces::kQueries) return query_id_allocator_.get(); @@ -5824,6 +5829,164 @@ void GLES2Implementation::GetInternalformativ( CheckGLError(); } +GLuint GLES2Implementation::GenPathsCHROMIUM(GLsizei range) { + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenPathsCHROMIUM(" << range + << ")"); + GPU_CLIENT_SINGLE_THREAD_CHECK(); + static const char kFunctionName[] = "glGenPathsCHROMIUM"; + if (range < 0) { + SetGLError(GL_INVALID_VALUE, kFunctionName, "range < 0"); + return 0; + } + if (!base::IsValueInRangeForNumericType<int32_t>(range)) { + SetGLError(GL_INVALID_OPERATION, kFunctionName, "range more than 32-bit"); + return 0; + } + if (range == 0) + return 0; + + GLuint first_client_id = 0; + GetRangeIdHandler(id_namespaces::kPaths) + ->MakeIdRange(this, range, &first_client_id); + + if (first_client_id == 0) { + // Ran out of id space. Is not specified to raise any gl errors. + return 0; + } + + helper_->GenPathsCHROMIUM(first_client_id, range); + + GPU_CLIENT_LOG_CODE_BLOCK({ + for (GLsizei i = 0; i < range; ++i) { + GPU_CLIENT_LOG(" " << i << ": " << (first_client_id + i)); + } + }); + CheckGLError(); + return first_client_id; +} + +void GLES2Implementation::DeletePathsCHROMIUM(GLuint first_client_id, + GLsizei range) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeletePathsCHROMIUM(" + << first_client_id << ", " << range << ")"); + static const char kFunctionName[] = "glDeletePathsCHROMIUM"; + + if (range < 0) { + SetGLError(GL_INVALID_VALUE, kFunctionName, "range < 0"); + return; + } + if (!base::IsValueInRangeForNumericType<int32_t>(range)) { + SetGLError(GL_INVALID_OPERATION, kFunctionName, "range more than 32-bit"); + return; + } + if (range == 0) + return; + + GLuint last_client_id; + if (!SafeAddUint32(first_client_id, range - 1, &last_client_id)) { + SetGLError(GL_INVALID_OPERATION, kFunctionName, "overflow"); + return; + } + + GetRangeIdHandler(id_namespaces::kPaths) + ->FreeIdRange(this, first_client_id, range, + &GLES2Implementation::DeletePathsCHROMIUMStub); + CheckGLError(); +} + +void GLES2Implementation::DeletePathsCHROMIUMStub(GLuint first_client_id, + GLsizei range) { + helper_->DeletePathsCHROMIUM(first_client_id, range); +} + +void GLES2Implementation::PathCommandsCHROMIUM(GLuint path, + GLsizei num_commands, + const GLubyte* commands, + GLsizei num_coords, + GLenum coord_type, + const void* coords) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPathCommandsCHROMIUM(" << path + << ", " << num_commands << ", " << commands << ", " + << num_coords << ", " << coords << ")"); + static const char kFunctionName[] = "glPathCommandsCHROMIUM"; + if (path == 0) { + SetGLError(GL_INVALID_VALUE, kFunctionName, "invalid path object"); + return; + } + if (num_commands < 0) { + SetGLError(GL_INVALID_VALUE, kFunctionName, "numCommands < 0"); + return; + } + if (num_commands != 0 && !commands) { + SetGLError(GL_INVALID_VALUE, kFunctionName, "missing commands"); + return; + } + if (num_coords < 0) { + SetGLError(GL_INVALID_VALUE, kFunctionName, "numCoords < 0"); + return; + } + if (num_coords != 0 && !coords) { + SetGLError(GL_INVALID_VALUE, kFunctionName, "missing coords"); + return; + } + uint32 coord_type_size = GLES2Util::GetGLTypeSizeForPathCoordType(coord_type); + if (coord_type_size == 0) { + SetGLError(GL_INVALID_ENUM, kFunctionName, "invalid coordType"); + return; + } + if (num_commands == 0) { + // No commands must mean no coords, thus nothing to memcpy. Let + // the service validate the call. Validate coord_type above, so + // that the parameters will be checked the in the same order + // regardless of num_commands. + helper_->PathCommandsCHROMIUM(path, num_commands, 0, 0, num_coords, + coord_type, 0, 0); + CheckGLError(); + return; + } + + uint32 coords_size; + if (!SafeMultiplyUint32(num_coords, coord_type_size, &coords_size)) { + SetGLError(GL_INVALID_OPERATION, kFunctionName, "overflow"); + return; + } + + uint32 required_buffer_size; + if (!SafeAddUint32(coords_size, num_commands, &required_buffer_size)) { + SetGLError(GL_INVALID_OPERATION, kFunctionName, "overflow"); + return; + } + + ScopedTransferBufferPtr buffer(required_buffer_size, helper_, + transfer_buffer_); + if (!buffer.valid() || buffer.size() < required_buffer_size) { + SetGLError(GL_OUT_OF_MEMORY, kFunctionName, "too large"); + return; + } + + uint32 coords_shm_id = 0; + uint32 coords_shm_offset = 0; + // Copy coords first because they need more strict alignment. + if (coords_size > 0) { + unsigned char* coords_addr = static_cast<unsigned char*>(buffer.address()); + memcpy(coords_addr, coords, coords_size); + coords_shm_id = buffer.shm_id(); + coords_shm_offset = buffer.offset(); + } + + DCHECK(num_commands > 0); + unsigned char* commands_addr = + static_cast<unsigned char*>(buffer.address()) + coords_size; + memcpy(commands_addr, commands, num_commands); + + helper_->PathCommandsCHROMIUM(path, num_commands, buffer.shm_id(), + buffer.offset() + coords_size, num_coords, + coord_type, coords_shm_id, coords_shm_offset); + CheckGLError(); +} + // 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/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h index c642f9a..3446e76 100644 --- a/gpu/command_buffer/client/gles2_implementation.h +++ b/gpu/command_buffer/client/gles2_implementation.h @@ -510,6 +510,7 @@ class GLES2_IMPL_EXPORT GLES2Implementation void DeleteFramebuffersStub(GLsizei n, const GLuint* framebuffers); void DeleteRenderbuffersStub(GLsizei n, const GLuint* renderbuffers); void DeleteTexturesStub(GLsizei n, const GLuint* textures); + void DeletePathsCHROMIUMStub(GLuint first_client_id, GLsizei range); void DeleteProgramStub(GLsizei n, const GLuint* programs); void DeleteShaderStub(GLsizei n, const GLuint* shaders); void DeleteVertexArraysOESStub(GLsizei n, const GLuint* arrays); @@ -593,6 +594,7 @@ class GLES2_IMPL_EXPORT GLES2Implementation bool SetCapabilityState(GLenum cap, bool enabled); IdHandlerInterface* GetIdHandler(int id_namespace) const; + RangeIdHandlerInterface* GetRangeIdHandler(int id_namespace) const; // IdAllocators for objects that can't be shared among contexts. // For now, used only for Queries. TODO(hj.r.chung) Should be added for // Framebuffer and Vertex array objects. diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h index 5cb7a65..bee4f9c 100644 --- a/gpu/command_buffer/client/gles2_implementation_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_autogen.h @@ -1053,6 +1053,47 @@ void MatrixLoadfCHROMIUM(GLenum matrixMode, const GLfloat* m) override; void MatrixLoadIdentityCHROMIUM(GLenum matrixMode) override; +GLuint GenPathsCHROMIUM(GLsizei range) override; + +void DeletePathsCHROMIUM(GLuint path, GLsizei range) override; + +GLboolean IsPathCHROMIUM(GLuint path) override; + +void PathCommandsCHROMIUM(GLuint path, + GLsizei numCommands, + const GLubyte* commands, + GLsizei numCoords, + GLenum coordType, + const GLvoid* coords) override; + +void PathParameterfCHROMIUM(GLuint path, GLenum pname, GLfloat value) override; + +void PathParameteriCHROMIUM(GLuint path, GLenum pname, GLint value) override; + +void PathStencilFuncCHROMIUM(GLenum func, GLint ref, GLuint mask) override; + +void StencilFillPathCHROMIUM(GLuint path, + GLenum fillMode, + GLuint mask) override; + +void StencilStrokePathCHROMIUM(GLuint path, + GLint reference, + GLuint mask) override; + +void CoverFillPathCHROMIUM(GLuint path, GLenum coverMode) override; + +void CoverStrokePathCHROMIUM(GLuint path, GLenum coverMode) override; + +void StencilThenCoverFillPathCHROMIUM(GLuint path, + GLenum fillMode, + GLuint mask, + GLenum coverMode) override; + +void StencilThenCoverStrokePathCHROMIUM(GLuint path, + GLint reference, + GLuint mask, + GLenum coverMode) override; + GLenum GetGraphicsResetStatusKHR() override; void BlendBarrierKHR() override; diff --git a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h index 8586fe3..79a7650 100644 --- a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h @@ -3462,6 +3462,123 @@ void GLES2Implementation::MatrixLoadIdentityCHROMIUM(GLenum matrixMode) { CheckGLError(); } +GLboolean GLES2Implementation::IsPathCHROMIUM(GLuint path) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + TRACE_EVENT0("gpu", "GLES2Implementation::IsPathCHROMIUM"); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsPathCHROMIUM(" << path << ")"); + typedef cmds::IsPathCHROMIUM::Result Result; + Result* result = GetResultAs<Result*>(); + if (!result) { + return GL_FALSE; + } + *result = 0; + helper_->IsPathCHROMIUM(path, GetResultShmId(), GetResultShmOffset()); + WaitForCmd(); + GLboolean result_value = *result != 0; + GPU_CLIENT_LOG("returned " << result_value); + CheckGLError(); + return result_value; +} + +void GLES2Implementation::PathParameterfCHROMIUM(GLuint path, + GLenum pname, + GLfloat value) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPathParameterfCHROMIUM(" << path + << ", " << GLES2Util::GetStringPathParameter(pname) << ", " + << value << ")"); + helper_->PathParameterfCHROMIUM(path, pname, value); + CheckGLError(); +} + +void GLES2Implementation::PathParameteriCHROMIUM(GLuint path, + GLenum pname, + GLint value) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPathParameteriCHROMIUM(" << path + << ", " << GLES2Util::GetStringPathParameter(pname) << ", " + << value << ")"); + helper_->PathParameteriCHROMIUM(path, pname, value); + CheckGLError(); +} + +void GLES2Implementation::PathStencilFuncCHROMIUM(GLenum func, + GLint ref, + GLuint mask) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPathStencilFuncCHROMIUM(" + << GLES2Util::GetStringCmpFunction(func) << ", " << ref + << ", " << mask << ")"); + helper_->PathStencilFuncCHROMIUM(func, ref, mask); + CheckGLError(); +} + +void GLES2Implementation::StencilFillPathCHROMIUM(GLuint path, + GLenum fillMode, + GLuint mask) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glStencilFillPathCHROMIUM(" << path + << ", " << GLES2Util::GetStringPathFillMode(fillMode) + << ", " << mask << ")"); + helper_->StencilFillPathCHROMIUM(path, fillMode, mask); + CheckGLError(); +} + +void GLES2Implementation::StencilStrokePathCHROMIUM(GLuint path, + GLint reference, + GLuint mask) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glStencilStrokePathCHROMIUM(" + << path << ", " << reference << ", " << mask << ")"); + helper_->StencilStrokePathCHROMIUM(path, reference, mask); + CheckGLError(); +} + +void GLES2Implementation::CoverFillPathCHROMIUM(GLuint path, GLenum coverMode) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCoverFillPathCHROMIUM(" << path + << ", " << GLES2Util::GetStringPathCoverMode(coverMode) + << ")"); + helper_->CoverFillPathCHROMIUM(path, coverMode); + CheckGLError(); +} + +void GLES2Implementation::CoverStrokePathCHROMIUM(GLuint path, + GLenum coverMode) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCoverStrokePathCHROMIUM(" << path + << ", " << GLES2Util::GetStringPathCoverMode(coverMode) + << ")"); + helper_->CoverStrokePathCHROMIUM(path, coverMode); + CheckGLError(); +} + +void GLES2Implementation::StencilThenCoverFillPathCHROMIUM(GLuint path, + GLenum fillMode, + GLuint mask, + GLenum coverMode) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG( + "[" << GetLogPrefix() << "] glStencilThenCoverFillPathCHROMIUM(" << path + << ", " << GLES2Util::GetStringPathFillMode(fillMode) << ", " << mask + << ", " << GLES2Util::GetStringPathCoverMode(coverMode) << ")"); + helper_->StencilThenCoverFillPathCHROMIUM(path, fillMode, mask, coverMode); + CheckGLError(); +} + +void GLES2Implementation::StencilThenCoverStrokePathCHROMIUM(GLuint path, + GLint reference, + GLuint mask, + GLenum coverMode) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << GetLogPrefix() + << "] glStencilThenCoverStrokePathCHROMIUM(" << path + << ", " << reference << ", " << mask << ", " + << GLES2Util::GetStringPathCoverMode(coverMode) << ")"); + helper_->StencilThenCoverStrokePathCHROMIUM(path, reference, mask, coverMode); + CheckGLError(); +} + void GLES2Implementation::BlendBarrierKHR() { GPU_CLIENT_SINGLE_THREAD_CHECK(); GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBlendBarrierKHR(" diff --git a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h index 7cf70eb..fef96d9 100644 --- a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h @@ -3119,4 +3119,136 @@ TEST_F(GLES2ImplementationTest, MatrixLoadIdentityCHROMIUM) { gl_->MatrixLoadIdentityCHROMIUM(GL_PATH_PROJECTION_CHROMIUM); EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); } +// TODO(zmo): Implement unit test for GenPathsCHROMIUM + +TEST_F(GLES2ImplementationTest, DeletePathsCHROMIUM) { + struct Cmds { + cmds::DeletePathsCHROMIUM cmd; + }; + Cmds expected; + expected.cmd.Init(1, 2); + + gl_->DeletePathsCHROMIUM(1, 2); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); +} + +TEST_F(GLES2ImplementationTest, IsPathCHROMIUM) { + struct Cmds { + cmds::IsPathCHROMIUM cmd; + }; + + Cmds expected; + ExpectedMemoryInfo result1 = + GetExpectedResultMemory(sizeof(cmds::IsPathCHROMIUM::Result)); + expected.cmd.Init(1, result1.id, result1.offset); + + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result1.ptr, uint32_t(GL_TRUE))) + .RetiresOnSaturation(); + + GLboolean result = gl_->IsPathCHROMIUM(1); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); + EXPECT_TRUE(result); +} +// TODO(zmo): Implement unit test for PathCommandsCHROMIUM + +TEST_F(GLES2ImplementationTest, PathParameterfCHROMIUM) { + struct Cmds { + cmds::PathParameterfCHROMIUM cmd; + }; + Cmds expected; + expected.cmd.Init(1, GL_PATH_STROKE_WIDTH_CHROMIUM, 3); + + gl_->PathParameterfCHROMIUM(1, GL_PATH_STROKE_WIDTH_CHROMIUM, 3); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); +} + +TEST_F(GLES2ImplementationTest, PathParameteriCHROMIUM) { + struct Cmds { + cmds::PathParameteriCHROMIUM cmd; + }; + Cmds expected; + expected.cmd.Init(1, GL_PATH_STROKE_WIDTH_CHROMIUM, 3); + + gl_->PathParameteriCHROMIUM(1, GL_PATH_STROKE_WIDTH_CHROMIUM, 3); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); +} + +TEST_F(GLES2ImplementationTest, PathStencilFuncCHROMIUM) { + struct Cmds { + cmds::PathStencilFuncCHROMIUM cmd; + }; + Cmds expected; + expected.cmd.Init(GL_NEVER, 2, 3); + + gl_->PathStencilFuncCHROMIUM(GL_NEVER, 2, 3); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); +} + +TEST_F(GLES2ImplementationTest, StencilFillPathCHROMIUM) { + struct Cmds { + cmds::StencilFillPathCHROMIUM cmd; + }; + Cmds expected; + expected.cmd.Init(1, GL_INVERT, 3); + + gl_->StencilFillPathCHROMIUM(1, GL_INVERT, 3); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); +} + +TEST_F(GLES2ImplementationTest, StencilStrokePathCHROMIUM) { + struct Cmds { + cmds::StencilStrokePathCHROMIUM cmd; + }; + Cmds expected; + expected.cmd.Init(1, 2, 3); + + gl_->StencilStrokePathCHROMIUM(1, 2, 3); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); +} + +TEST_F(GLES2ImplementationTest, CoverFillPathCHROMIUM) { + struct Cmds { + cmds::CoverFillPathCHROMIUM cmd; + }; + Cmds expected; + expected.cmd.Init(1, GL_CONVEX_HULL_CHROMIUM); + + gl_->CoverFillPathCHROMIUM(1, GL_CONVEX_HULL_CHROMIUM); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); +} + +TEST_F(GLES2ImplementationTest, CoverStrokePathCHROMIUM) { + struct Cmds { + cmds::CoverStrokePathCHROMIUM cmd; + }; + Cmds expected; + expected.cmd.Init(1, GL_CONVEX_HULL_CHROMIUM); + + gl_->CoverStrokePathCHROMIUM(1, GL_CONVEX_HULL_CHROMIUM); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); +} + +TEST_F(GLES2ImplementationTest, StencilThenCoverFillPathCHROMIUM) { + struct Cmds { + cmds::StencilThenCoverFillPathCHROMIUM cmd; + }; + Cmds expected; + expected.cmd.Init(1, GL_INVERT, 3, GL_CONVEX_HULL_CHROMIUM); + + gl_->StencilThenCoverFillPathCHROMIUM(1, GL_INVERT, 3, + GL_CONVEX_HULL_CHROMIUM); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); +} + +TEST_F(GLES2ImplementationTest, StencilThenCoverStrokePathCHROMIUM) { + struct Cmds { + cmds::StencilThenCoverStrokePathCHROMIUM cmd; + }; + Cmds expected; + expected.cmd.Init(1, 2, 3, GL_CONVEX_HULL_CHROMIUM); + + gl_->StencilThenCoverStrokePathCHROMIUM(1, 2, 3, GL_CONVEX_HULL_CHROMIUM); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); +} #endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_UNITTEST_AUTOGEN_H_ diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h index 5e61f11..99d0577 100644 --- a/gpu/command_buffer/client/gles2_interface_autogen.h +++ b/gpu/command_buffer/client/gles2_interface_autogen.h @@ -781,6 +781,36 @@ virtual void ScheduleOverlayPlaneCHROMIUM(GLint plane_z_order, virtual void SwapInterval(GLint interval) = 0; virtual void MatrixLoadfCHROMIUM(GLenum matrixMode, const GLfloat* m) = 0; virtual void MatrixLoadIdentityCHROMIUM(GLenum matrixMode) = 0; +virtual GLuint GenPathsCHROMIUM(GLsizei range) = 0; +virtual void DeletePathsCHROMIUM(GLuint path, GLsizei range) = 0; +virtual GLboolean IsPathCHROMIUM(GLuint path) = 0; +virtual void PathCommandsCHROMIUM(GLuint path, + GLsizei numCommands, + const GLubyte* commands, + GLsizei numCoords, + GLenum coordType, + const GLvoid* coords) = 0; +virtual void PathParameterfCHROMIUM(GLuint path, + GLenum pname, + GLfloat value) = 0; +virtual void PathParameteriCHROMIUM(GLuint path, GLenum pname, GLint value) = 0; +virtual void PathStencilFuncCHROMIUM(GLenum func, GLint ref, GLuint mask) = 0; +virtual void StencilFillPathCHROMIUM(GLuint path, + GLenum fillMode, + GLuint mask) = 0; +virtual void StencilStrokePathCHROMIUM(GLuint path, + GLint reference, + GLuint mask) = 0; +virtual void CoverFillPathCHROMIUM(GLuint path, GLenum coverMode) = 0; +virtual void CoverStrokePathCHROMIUM(GLuint path, GLenum coverMode) = 0; +virtual void StencilThenCoverFillPathCHROMIUM(GLuint path, + GLenum fillMode, + GLuint mask, + GLenum coverMode) = 0; +virtual void StencilThenCoverStrokePathCHROMIUM(GLuint path, + GLint reference, + GLuint mask, + GLenum coverMode) = 0; virtual GLenum GetGraphicsResetStatusKHR() = 0; virtual void BlendBarrierKHR() = 0; #endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_AUTOGEN_H_ diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h index 1f70750..41358fb 100644 --- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h +++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h @@ -759,6 +759,34 @@ void ScheduleOverlayPlaneCHROMIUM(GLint plane_z_order, void SwapInterval(GLint interval) override; void MatrixLoadfCHROMIUM(GLenum matrixMode, const GLfloat* m) override; void MatrixLoadIdentityCHROMIUM(GLenum matrixMode) override; +GLuint GenPathsCHROMIUM(GLsizei range) override; +void DeletePathsCHROMIUM(GLuint path, GLsizei range) override; +GLboolean IsPathCHROMIUM(GLuint path) override; +void PathCommandsCHROMIUM(GLuint path, + GLsizei numCommands, + const GLubyte* commands, + GLsizei numCoords, + GLenum coordType, + const GLvoid* coords) override; +void PathParameterfCHROMIUM(GLuint path, GLenum pname, GLfloat value) override; +void PathParameteriCHROMIUM(GLuint path, GLenum pname, GLint value) override; +void PathStencilFuncCHROMIUM(GLenum func, GLint ref, GLuint mask) override; +void StencilFillPathCHROMIUM(GLuint path, + GLenum fillMode, + GLuint mask) override; +void StencilStrokePathCHROMIUM(GLuint path, + GLint reference, + GLuint mask) override; +void CoverFillPathCHROMIUM(GLuint path, GLenum coverMode) override; +void CoverStrokePathCHROMIUM(GLuint path, GLenum coverMode) override; +void StencilThenCoverFillPathCHROMIUM(GLuint path, + GLenum fillMode, + GLuint mask, + GLenum coverMode) override; +void StencilThenCoverStrokePathCHROMIUM(GLuint path, + GLint reference, + GLuint mask, + GLenum coverMode) override; GLenum GetGraphicsResetStatusKHR() override; void BlendBarrierKHR() override; #endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_STUB_AUTOGEN_H_ diff --git a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h index cf1baa2..6058760 100644 --- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h +++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h @@ -1290,6 +1290,60 @@ void GLES2InterfaceStub::MatrixLoadfCHROMIUM(GLenum /* matrixMode */, } void GLES2InterfaceStub::MatrixLoadIdentityCHROMIUM(GLenum /* matrixMode */) { } +GLuint GLES2InterfaceStub::GenPathsCHROMIUM(GLsizei /* range */) { + return 0; +} +void GLES2InterfaceStub::DeletePathsCHROMIUM(GLuint /* path */, + GLsizei /* range */) { +} +GLboolean GLES2InterfaceStub::IsPathCHROMIUM(GLuint /* path */) { + return 0; +} +void GLES2InterfaceStub::PathCommandsCHROMIUM(GLuint /* path */, + GLsizei /* numCommands */, + const GLubyte* /* commands */, + GLsizei /* numCoords */, + GLenum /* coordType */, + const GLvoid* /* coords */) { +} +void GLES2InterfaceStub::PathParameterfCHROMIUM(GLuint /* path */, + GLenum /* pname */, + GLfloat /* value */) { +} +void GLES2InterfaceStub::PathParameteriCHROMIUM(GLuint /* path */, + GLenum /* pname */, + GLint /* value */) { +} +void GLES2InterfaceStub::PathStencilFuncCHROMIUM(GLenum /* func */, + GLint /* ref */, + GLuint /* mask */) { +} +void GLES2InterfaceStub::StencilFillPathCHROMIUM(GLuint /* path */, + GLenum /* fillMode */, + GLuint /* mask */) { +} +void GLES2InterfaceStub::StencilStrokePathCHROMIUM(GLuint /* path */, + GLint /* reference */, + GLuint /* mask */) { +} +void GLES2InterfaceStub::CoverFillPathCHROMIUM(GLuint /* path */, + GLenum /* coverMode */) { +} +void GLES2InterfaceStub::CoverStrokePathCHROMIUM(GLuint /* path */, + GLenum /* coverMode */) { +} +void GLES2InterfaceStub::StencilThenCoverFillPathCHROMIUM( + GLuint /* path */, + GLenum /* fillMode */, + GLuint /* mask */, + GLenum /* coverMode */) { +} +void GLES2InterfaceStub::StencilThenCoverStrokePathCHROMIUM( + GLuint /* path */, + GLint /* reference */, + GLuint /* mask */, + GLenum /* coverMode */) { +} GLenum GLES2InterfaceStub::GetGraphicsResetStatusKHR() { return 0; } diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h index 30743ea..ed48158 100644 --- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h +++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h @@ -759,6 +759,34 @@ void ScheduleOverlayPlaneCHROMIUM(GLint plane_z_order, void SwapInterval(GLint interval) override; void MatrixLoadfCHROMIUM(GLenum matrixMode, const GLfloat* m) override; void MatrixLoadIdentityCHROMIUM(GLenum matrixMode) override; +GLuint GenPathsCHROMIUM(GLsizei range) override; +void DeletePathsCHROMIUM(GLuint path, GLsizei range) override; +GLboolean IsPathCHROMIUM(GLuint path) override; +void PathCommandsCHROMIUM(GLuint path, + GLsizei numCommands, + const GLubyte* commands, + GLsizei numCoords, + GLenum coordType, + const GLvoid* coords) override; +void PathParameterfCHROMIUM(GLuint path, GLenum pname, GLfloat value) override; +void PathParameteriCHROMIUM(GLuint path, GLenum pname, GLint value) override; +void PathStencilFuncCHROMIUM(GLenum func, GLint ref, GLuint mask) override; +void StencilFillPathCHROMIUM(GLuint path, + GLenum fillMode, + GLuint mask) override; +void StencilStrokePathCHROMIUM(GLuint path, + GLint reference, + GLuint mask) override; +void CoverFillPathCHROMIUM(GLuint path, GLenum coverMode) override; +void CoverStrokePathCHROMIUM(GLuint path, GLenum coverMode) override; +void StencilThenCoverFillPathCHROMIUM(GLuint path, + GLenum fillMode, + GLuint mask, + GLenum coverMode) override; +void StencilThenCoverStrokePathCHROMIUM(GLuint path, + GLint reference, + GLuint mask, + GLenum coverMode) override; GLenum GetGraphicsResetStatusKHR() override; void BlendBarrierKHR() override; #endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_TRACE_IMPLEMENTATION_AUTOGEN_H_ diff --git a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h index 13c215f..a0b41a2 100644 --- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h +++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h @@ -2206,6 +2206,99 @@ void GLES2TraceImplementation::MatrixLoadIdentityCHROMIUM(GLenum matrixMode) { gl_->MatrixLoadIdentityCHROMIUM(matrixMode); } +GLuint GLES2TraceImplementation::GenPathsCHROMIUM(GLsizei range) { + TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GenPathsCHROMIUM"); + return gl_->GenPathsCHROMIUM(range); +} + +void GLES2TraceImplementation::DeletePathsCHROMIUM(GLuint path, GLsizei range) { + TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DeletePathsCHROMIUM"); + gl_->DeletePathsCHROMIUM(path, range); +} + +GLboolean GLES2TraceImplementation::IsPathCHROMIUM(GLuint path) { + TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::IsPathCHROMIUM"); + return gl_->IsPathCHROMIUM(path); +} + +void GLES2TraceImplementation::PathCommandsCHROMIUM(GLuint path, + GLsizei numCommands, + const GLubyte* commands, + GLsizei numCoords, + GLenum coordType, + const GLvoid* coords) { + TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::PathCommandsCHROMIUM"); + gl_->PathCommandsCHROMIUM(path, numCommands, commands, numCoords, coordType, + coords); +} + +void GLES2TraceImplementation::PathParameterfCHROMIUM(GLuint path, + GLenum pname, + GLfloat value) { + TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::PathParameterfCHROMIUM"); + gl_->PathParameterfCHROMIUM(path, pname, value); +} + +void GLES2TraceImplementation::PathParameteriCHROMIUM(GLuint path, + GLenum pname, + GLint value) { + TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::PathParameteriCHROMIUM"); + gl_->PathParameteriCHROMIUM(path, pname, value); +} + +void GLES2TraceImplementation::PathStencilFuncCHROMIUM(GLenum func, + GLint ref, + GLuint mask) { + TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::PathStencilFuncCHROMIUM"); + gl_->PathStencilFuncCHROMIUM(func, ref, mask); +} + +void GLES2TraceImplementation::StencilFillPathCHROMIUM(GLuint path, + GLenum fillMode, + GLuint mask) { + TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::StencilFillPathCHROMIUM"); + gl_->StencilFillPathCHROMIUM(path, fillMode, mask); +} + +void GLES2TraceImplementation::StencilStrokePathCHROMIUM(GLuint path, + GLint reference, + GLuint mask) { + TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::StencilStrokePathCHROMIUM"); + gl_->StencilStrokePathCHROMIUM(path, reference, mask); +} + +void GLES2TraceImplementation::CoverFillPathCHROMIUM(GLuint path, + GLenum coverMode) { + TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::CoverFillPathCHROMIUM"); + gl_->CoverFillPathCHROMIUM(path, coverMode); +} + +void GLES2TraceImplementation::CoverStrokePathCHROMIUM(GLuint path, + GLenum coverMode) { + TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::CoverStrokePathCHROMIUM"); + gl_->CoverStrokePathCHROMIUM(path, coverMode); +} + +void GLES2TraceImplementation::StencilThenCoverFillPathCHROMIUM( + GLuint path, + GLenum fillMode, + GLuint mask, + GLenum coverMode) { + TRACE_EVENT_BINARY_EFFICIENT0("gpu", + "GLES2Trace::StencilThenCoverFillPathCHROMIUM"); + gl_->StencilThenCoverFillPathCHROMIUM(path, fillMode, mask, coverMode); +} + +void GLES2TraceImplementation::StencilThenCoverStrokePathCHROMIUM( + GLuint path, + GLint reference, + GLuint mask, + GLenum coverMode) { + TRACE_EVENT_BINARY_EFFICIENT0( + "gpu", "GLES2Trace::StencilThenCoverStrokePathCHROMIUM"); + gl_->StencilThenCoverStrokePathCHROMIUM(path, reference, mask, coverMode); +} + GLenum GLES2TraceImplementation::GetGraphicsResetStatusKHR() { TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetGraphicsResetStatusKHR"); return gl_->GetGraphicsResetStatusKHR(); diff --git a/gpu/command_buffer/client/share_group.cc b/gpu/command_buffer/client/share_group.cc index 32e853b..e6ed66d 100644 --- a/gpu/command_buffer/client/share_group.cc +++ b/gpu/command_buffer/client/share_group.cc @@ -318,6 +318,35 @@ class NonReusedIdHandler : public IdHandlerInterface { GLuint last_id_; }; +class RangeIdHandler : public RangeIdHandlerInterface { + public: + RangeIdHandler() {} + + void MakeIdRange(GLES2Implementation* /*gl_impl*/, + GLsizei n, + GLuint* first_id) override { + base::AutoLock auto_lock(lock_); + *first_id = id_allocator_.AllocateIDRange(n); + } + + void FreeIdRange(GLES2Implementation* gl_impl, + const GLuint first_id, + GLsizei range, + DeleteRangeFn delete_fn) override { + base::AutoLock auto_lock(lock_); + DCHECK(range > 0); + id_allocator_.FreeIDRange(first_id, range); + (gl_impl->*delete_fn)(first_id, range); + gl_impl->helper()->CommandBufferHelper::OrderingBarrier(); + } + + void FreeContext(GLES2Implementation* gl_impl) override {} + + private: + base::Lock lock_; + IdAllocator id_allocator_; +}; + ShareGroup::ShareGroup(bool bind_generates_resource) : bind_generates_resource_(bind_generates_resource) { if (bind_generates_resource) { @@ -338,6 +367,9 @@ ShareGroup::ShareGroup(bool bind_generates_resource) } } program_info_manager_.reset(new ProgramInfoManager); + for (auto& range_id_handler : range_id_handlers_) { + range_id_handler.reset(new RangeIdHandler()); + } } void ShareGroup::set_program_info_manager(ProgramInfoManager* manager) { diff --git a/gpu/command_buffer/client/share_group.h b/gpu/command_buffer/client/share_group.h index c150004..2a6acc5 100644 --- a/gpu/command_buffer/client/share_group.h +++ b/gpu/command_buffer/client/share_group.h @@ -19,6 +19,8 @@ class GLES2ImplementationTest; class ProgramInfoManager; typedef void (GLES2Implementation::*DeleteFn)(GLsizei n, const GLuint* ids); +typedef void (GLES2Implementation::*DeleteRangeFn)(const GLuint first_id, + GLsizei range); typedef void (GLES2Implementation::*BindFn)(GLenum target, GLuint id); typedef void (GLES2Implementation::*BindIndexedFn)( \ GLenum target, GLuint index, GLuint id); @@ -86,6 +88,27 @@ class IdHandlerInterface { virtual void FreeContext(GLES2Implementation* gl_impl) = 0; }; +class RangeIdHandlerInterface { + public: + RangeIdHandlerInterface() {} + virtual ~RangeIdHandlerInterface() {} + + // Makes a continuous range of ids. Stores the first allocated id to + // |first_id| or 0 if allocation failed. + virtual void MakeIdRange(GLES2Implementation* gl_impl, + GLsizei n, + GLuint* first_id) = 0; + + // Frees a continuous |range| of ids beginning at |first_id|. + virtual void FreeIdRange(GLES2Implementation* gl_impl, + const GLuint first_id, + GLsizei range, + DeleteRangeFn delete_fn) = 0; + + // Called when a context in the share group is destructed. + virtual void FreeContext(GLES2Implementation* gl_impl) = 0; +}; + // ShareGroup manages shared resources for contexts that are sharing resources. class GLES2_IMPL_EXPORT ShareGroup : public gpu::RefCountedThreadSafe<ShareGroup> { @@ -100,6 +123,10 @@ class GLES2_IMPL_EXPORT ShareGroup return id_handlers_[namespace_id].get(); } + RangeIdHandlerInterface* GetRangeIdHandler(int range_namespace_id) const { + return range_id_handlers_[range_namespace_id].get(); + } + ProgramInfoManager* program_info_manager() { return program_info_manager_.get(); } @@ -108,6 +135,9 @@ class GLES2_IMPL_EXPORT ShareGroup for (int i = 0; i < id_namespaces::kNumIdNamespaces; ++i) { id_handlers_[i]->FreeContext(gl_impl); } + for (auto& range_id_handler : range_id_handlers_) { + range_id_handler->FreeContext(gl_impl); + } } private: @@ -119,6 +149,8 @@ class GLES2_IMPL_EXPORT ShareGroup void set_program_info_manager(ProgramInfoManager* manager); scoped_ptr<IdHandlerInterface> id_handlers_[id_namespaces::kNumIdNamespaces]; + scoped_ptr<RangeIdHandlerInterface> + range_id_handlers_[id_namespaces::kNumRangeIdNamespaces]; scoped_ptr<ProgramInfoManager> program_info_manager_; bool bind_generates_resource_; diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt index bcd4204..890a5db 100644 --- a/gpu/command_buffer/cmd_buffer_functions.txt +++ b/gpu/command_buffer/cmd_buffer_functions.txt @@ -314,6 +314,19 @@ GL_APICALL void GL_APIENTRY glSwapInterval (GLint interval); // Extension CHROMIUM_path_rendering. GL_APICALL void GL_APIENTRY glMatrixLoadfCHROMIUM (GLenumMatrixMode matrixMode, const GLfloat* m); GL_APICALL void GL_APIENTRY glMatrixLoadIdentityCHROMIUM (GLenumMatrixMode matrixMode); +GL_APICALL GLuint GL_APIENTRY glGenPathsCHROMIUM (GLsizei range); +GL_APICALL void GL_APIENTRY glDeletePathsCHROMIUM (GLidPath path, GLsizei range); +GL_APICALL GLboolean GL_APIENTRY glIsPathCHROMIUM (GLidPath path); +GL_APICALL void GL_APIENTRY glPathCommandsCHROMIUM (GLidPath path, GLsizei numCommands, const GLubyte* commands, GLsizei numCoords, GLenumPathCoordType coordType, const GLvoid* coords); +GL_APICALL void GL_APIENTRY glPathParameterfCHROMIUM (GLidPath path, GLenumPathParameter pname, GLfloat value); +GL_APICALL void GL_APIENTRY glPathParameteriCHROMIUM (GLidPath path, GLenumPathParameter pname, GLint value); +GL_APICALL void GL_APIENTRY glPathStencilFuncCHROMIUM (GLenumCmpFunction func, GLint ref, GLuint mask); +GL_APICALL void GL_APIENTRY glStencilFillPathCHROMIUM (GLidPath path, GLenumPathFillMode fillMode, GLuint mask); +GL_APICALL void GL_APIENTRY glStencilStrokePathCHROMIUM (GLidPath path, GLint reference, GLuint mask); +GL_APICALL void GL_APIENTRY glCoverFillPathCHROMIUM (GLidPath path, GLenumPathCoverMode coverMode); +GL_APICALL void GL_APIENTRY glCoverStrokePathCHROMIUM (GLidPath path, GLenumPathCoverMode coverMode); +GL_APICALL void GL_APIENTRY glStencilThenCoverFillPathCHROMIUM (GLidPath path, GLenumPathFillMode fillMode, GLuint mask, GLenumPathCoverMode coverMode); +GL_APICALL void GL_APIENTRY glStencilThenCoverStrokePathCHROMIUM (GLidPath path, GLint reference, GLuint mask, GLenumPathCoverMode coverMode); // Extension KHR_robustness GL_APICALL GLenum GL_APIENTRY glGetGraphicsResetStatusKHR (void); diff --git a/gpu/command_buffer/common/gles2_cmd_format.h b/gpu/command_buffer/common/gles2_cmd_format.h index db63594..325c334 100644 --- a/gpu/command_buffer/common/gles2_cmd_format.h +++ b/gpu/command_buffer/common/gles2_cmd_format.h @@ -70,12 +70,15 @@ enum IdNamespaces { kNumIdNamespaces }; +enum RangeIdNamespaces { kPaths, kNumRangeIdNamespaces }; + // These numbers must not change static_assert(kBuffers == 0, "kBuffers should equal 0"); static_assert(kFramebuffers == 1, "kFramebuffers should equal 1"); static_assert(kProgramsAndShaders == 2, "kProgramsAndShaders should equal 2"); static_assert(kRenderbuffers == 3, "kRenderbuffers should equal 3"); static_assert(kTextures == 4, "kTextures should equal 4"); +static_assert(kPaths == 0, "kPaths should equal 0"); } // namespace id_namespaces diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h index e7a6272..ded8b6f 100644 --- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h @@ -13780,6 +13780,590 @@ static_assert(offsetof(MatrixLoadIdentityCHROMIUM, header) == 0, static_assert(offsetof(MatrixLoadIdentityCHROMIUM, matrixMode) == 4, "offset of MatrixLoadIdentityCHROMIUM matrixMode should be 4"); +struct GenPathsCHROMIUM { + typedef GenPathsCHROMIUM ValueType; + static const CommandId kCmdId = kGenPathsCHROMIUM; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); + + static uint32_t ComputeSize() { + return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { header.SetCmd<ValueType>(); } + + void Init(GLuint _first_client_id, GLsizei _range) { + SetHeader(); + first_client_id = _first_client_id; + range = _range; + } + + void* Set(void* cmd, GLuint _first_client_id, GLsizei _range) { + static_cast<ValueType*>(cmd)->Init(_first_client_id, _range); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32_t first_client_id; + int32_t range; +}; + +static_assert(sizeof(GenPathsCHROMIUM) == 12, + "size of GenPathsCHROMIUM should be 12"); +static_assert(offsetof(GenPathsCHROMIUM, header) == 0, + "offset of GenPathsCHROMIUM header should be 0"); +static_assert(offsetof(GenPathsCHROMIUM, first_client_id) == 4, + "offset of GenPathsCHROMIUM first_client_id should be 4"); +static_assert(offsetof(GenPathsCHROMIUM, range) == 8, + "offset of GenPathsCHROMIUM range should be 8"); + +struct DeletePathsCHROMIUM { + typedef DeletePathsCHROMIUM ValueType; + static const CommandId kCmdId = kDeletePathsCHROMIUM; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); + + static uint32_t ComputeSize() { + return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { header.SetCmd<ValueType>(); } + + void Init(GLuint _first_client_id, GLsizei _range) { + SetHeader(); + first_client_id = _first_client_id; + range = _range; + } + + void* Set(void* cmd, GLuint _first_client_id, GLsizei _range) { + static_cast<ValueType*>(cmd)->Init(_first_client_id, _range); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32_t first_client_id; + int32_t range; +}; + +static_assert(sizeof(DeletePathsCHROMIUM) == 12, + "size of DeletePathsCHROMIUM should be 12"); +static_assert(offsetof(DeletePathsCHROMIUM, header) == 0, + "offset of DeletePathsCHROMIUM header should be 0"); +static_assert(offsetof(DeletePathsCHROMIUM, first_client_id) == 4, + "offset of DeletePathsCHROMIUM first_client_id should be 4"); +static_assert(offsetof(DeletePathsCHROMIUM, range) == 8, + "offset of DeletePathsCHROMIUM range should be 8"); + +struct IsPathCHROMIUM { + typedef IsPathCHROMIUM ValueType; + static const CommandId kCmdId = kIsPathCHROMIUM; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); + + typedef uint32_t Result; + + static uint32_t ComputeSize() { + return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { header.SetCmd<ValueType>(); } + + void Init(GLuint _path, + uint32_t _result_shm_id, + uint32_t _result_shm_offset) { + SetHeader(); + path = _path; + result_shm_id = _result_shm_id; + result_shm_offset = _result_shm_offset; + } + + void* Set(void* cmd, + GLuint _path, + uint32_t _result_shm_id, + uint32_t _result_shm_offset) { + static_cast<ValueType*>(cmd) + ->Init(_path, _result_shm_id, _result_shm_offset); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32_t path; + uint32_t result_shm_id; + uint32_t result_shm_offset; +}; + +static_assert(sizeof(IsPathCHROMIUM) == 16, + "size of IsPathCHROMIUM should be 16"); +static_assert(offsetof(IsPathCHROMIUM, header) == 0, + "offset of IsPathCHROMIUM header should be 0"); +static_assert(offsetof(IsPathCHROMIUM, path) == 4, + "offset of IsPathCHROMIUM path should be 4"); +static_assert(offsetof(IsPathCHROMIUM, result_shm_id) == 8, + "offset of IsPathCHROMIUM result_shm_id should be 8"); +static_assert(offsetof(IsPathCHROMIUM, result_shm_offset) == 12, + "offset of IsPathCHROMIUM result_shm_offset should be 12"); + +struct PathCommandsCHROMIUM { + typedef PathCommandsCHROMIUM ValueType; + static const CommandId kCmdId = kPathCommandsCHROMIUM; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); + + static uint32_t ComputeSize() { + return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { header.SetCmd<ValueType>(); } + + void Init(GLuint _path, + GLsizei _numCommands, + uint32_t _commands_shm_id, + uint32_t _commands_shm_offset, + GLsizei _numCoords, + GLenum _coordType, + uint32_t _coords_shm_id, + uint32_t _coords_shm_offset) { + SetHeader(); + path = _path; + numCommands = _numCommands; + commands_shm_id = _commands_shm_id; + commands_shm_offset = _commands_shm_offset; + numCoords = _numCoords; + coordType = _coordType; + coords_shm_id = _coords_shm_id; + coords_shm_offset = _coords_shm_offset; + } + + void* Set(void* cmd, + GLuint _path, + GLsizei _numCommands, + uint32_t _commands_shm_id, + uint32_t _commands_shm_offset, + GLsizei _numCoords, + GLenum _coordType, + uint32_t _coords_shm_id, + uint32_t _coords_shm_offset) { + static_cast<ValueType*>(cmd) + ->Init(_path, _numCommands, _commands_shm_id, _commands_shm_offset, + _numCoords, _coordType, _coords_shm_id, _coords_shm_offset); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32_t path; + int32_t numCommands; + uint32_t commands_shm_id; + uint32_t commands_shm_offset; + int32_t numCoords; + uint32_t coordType; + uint32_t coords_shm_id; + uint32_t coords_shm_offset; +}; + +static_assert(sizeof(PathCommandsCHROMIUM) == 36, + "size of PathCommandsCHROMIUM should be 36"); +static_assert(offsetof(PathCommandsCHROMIUM, header) == 0, + "offset of PathCommandsCHROMIUM header should be 0"); +static_assert(offsetof(PathCommandsCHROMIUM, path) == 4, + "offset of PathCommandsCHROMIUM path should be 4"); +static_assert(offsetof(PathCommandsCHROMIUM, numCommands) == 8, + "offset of PathCommandsCHROMIUM numCommands should be 8"); +static_assert(offsetof(PathCommandsCHROMIUM, commands_shm_id) == 12, + "offset of PathCommandsCHROMIUM commands_shm_id should be 12"); +static_assert( + offsetof(PathCommandsCHROMIUM, commands_shm_offset) == 16, + "offset of PathCommandsCHROMIUM commands_shm_offset should be 16"); +static_assert(offsetof(PathCommandsCHROMIUM, numCoords) == 20, + "offset of PathCommandsCHROMIUM numCoords should be 20"); +static_assert(offsetof(PathCommandsCHROMIUM, coordType) == 24, + "offset of PathCommandsCHROMIUM coordType should be 24"); +static_assert(offsetof(PathCommandsCHROMIUM, coords_shm_id) == 28, + "offset of PathCommandsCHROMIUM coords_shm_id should be 28"); +static_assert(offsetof(PathCommandsCHROMIUM, coords_shm_offset) == 32, + "offset of PathCommandsCHROMIUM coords_shm_offset should be 32"); + +struct PathParameterfCHROMIUM { + typedef PathParameterfCHROMIUM ValueType; + static const CommandId kCmdId = kPathParameterfCHROMIUM; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); + + static uint32_t ComputeSize() { + return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { header.SetCmd<ValueType>(); } + + void Init(GLuint _path, GLenum _pname, GLfloat _value) { + SetHeader(); + path = _path; + pname = _pname; + value = _value; + } + + void* Set(void* cmd, GLuint _path, GLenum _pname, GLfloat _value) { + static_cast<ValueType*>(cmd)->Init(_path, _pname, _value); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32_t path; + uint32_t pname; + float value; +}; + +static_assert(sizeof(PathParameterfCHROMIUM) == 16, + "size of PathParameterfCHROMIUM should be 16"); +static_assert(offsetof(PathParameterfCHROMIUM, header) == 0, + "offset of PathParameterfCHROMIUM header should be 0"); +static_assert(offsetof(PathParameterfCHROMIUM, path) == 4, + "offset of PathParameterfCHROMIUM path should be 4"); +static_assert(offsetof(PathParameterfCHROMIUM, pname) == 8, + "offset of PathParameterfCHROMIUM pname should be 8"); +static_assert(offsetof(PathParameterfCHROMIUM, value) == 12, + "offset of PathParameterfCHROMIUM value should be 12"); + +struct PathParameteriCHROMIUM { + typedef PathParameteriCHROMIUM ValueType; + static const CommandId kCmdId = kPathParameteriCHROMIUM; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); + + static uint32_t ComputeSize() { + return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { header.SetCmd<ValueType>(); } + + void Init(GLuint _path, GLenum _pname, GLint _value) { + SetHeader(); + path = _path; + pname = _pname; + value = _value; + } + + void* Set(void* cmd, GLuint _path, GLenum _pname, GLint _value) { + static_cast<ValueType*>(cmd)->Init(_path, _pname, _value); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32_t path; + uint32_t pname; + int32_t value; +}; + +static_assert(sizeof(PathParameteriCHROMIUM) == 16, + "size of PathParameteriCHROMIUM should be 16"); +static_assert(offsetof(PathParameteriCHROMIUM, header) == 0, + "offset of PathParameteriCHROMIUM header should be 0"); +static_assert(offsetof(PathParameteriCHROMIUM, path) == 4, + "offset of PathParameteriCHROMIUM path should be 4"); +static_assert(offsetof(PathParameteriCHROMIUM, pname) == 8, + "offset of PathParameteriCHROMIUM pname should be 8"); +static_assert(offsetof(PathParameteriCHROMIUM, value) == 12, + "offset of PathParameteriCHROMIUM value should be 12"); + +struct PathStencilFuncCHROMIUM { + typedef PathStencilFuncCHROMIUM ValueType; + static const CommandId kCmdId = kPathStencilFuncCHROMIUM; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); + + static uint32_t ComputeSize() { + return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { header.SetCmd<ValueType>(); } + + void Init(GLenum _func, GLint _ref, GLuint _mask) { + SetHeader(); + func = _func; + ref = _ref; + mask = _mask; + } + + void* Set(void* cmd, GLenum _func, GLint _ref, GLuint _mask) { + static_cast<ValueType*>(cmd)->Init(_func, _ref, _mask); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32_t func; + int32_t ref; + uint32_t mask; +}; + +static_assert(sizeof(PathStencilFuncCHROMIUM) == 16, + "size of PathStencilFuncCHROMIUM should be 16"); +static_assert(offsetof(PathStencilFuncCHROMIUM, header) == 0, + "offset of PathStencilFuncCHROMIUM header should be 0"); +static_assert(offsetof(PathStencilFuncCHROMIUM, func) == 4, + "offset of PathStencilFuncCHROMIUM func should be 4"); +static_assert(offsetof(PathStencilFuncCHROMIUM, ref) == 8, + "offset of PathStencilFuncCHROMIUM ref should be 8"); +static_assert(offsetof(PathStencilFuncCHROMIUM, mask) == 12, + "offset of PathStencilFuncCHROMIUM mask should be 12"); + +struct StencilFillPathCHROMIUM { + typedef StencilFillPathCHROMIUM ValueType; + static const CommandId kCmdId = kStencilFillPathCHROMIUM; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); + + static uint32_t ComputeSize() { + return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { header.SetCmd<ValueType>(); } + + void Init(GLuint _path, GLenum _fillMode, GLuint _mask) { + SetHeader(); + path = _path; + fillMode = _fillMode; + mask = _mask; + } + + void* Set(void* cmd, GLuint _path, GLenum _fillMode, GLuint _mask) { + static_cast<ValueType*>(cmd)->Init(_path, _fillMode, _mask); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32_t path; + uint32_t fillMode; + uint32_t mask; +}; + +static_assert(sizeof(StencilFillPathCHROMIUM) == 16, + "size of StencilFillPathCHROMIUM should be 16"); +static_assert(offsetof(StencilFillPathCHROMIUM, header) == 0, + "offset of StencilFillPathCHROMIUM header should be 0"); +static_assert(offsetof(StencilFillPathCHROMIUM, path) == 4, + "offset of StencilFillPathCHROMIUM path should be 4"); +static_assert(offsetof(StencilFillPathCHROMIUM, fillMode) == 8, + "offset of StencilFillPathCHROMIUM fillMode should be 8"); +static_assert(offsetof(StencilFillPathCHROMIUM, mask) == 12, + "offset of StencilFillPathCHROMIUM mask should be 12"); + +struct StencilStrokePathCHROMIUM { + typedef StencilStrokePathCHROMIUM ValueType; + static const CommandId kCmdId = kStencilStrokePathCHROMIUM; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); + + static uint32_t ComputeSize() { + return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { header.SetCmd<ValueType>(); } + + void Init(GLuint _path, GLint _reference, GLuint _mask) { + SetHeader(); + path = _path; + reference = _reference; + mask = _mask; + } + + void* Set(void* cmd, GLuint _path, GLint _reference, GLuint _mask) { + static_cast<ValueType*>(cmd)->Init(_path, _reference, _mask); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32_t path; + int32_t reference; + uint32_t mask; +}; + +static_assert(sizeof(StencilStrokePathCHROMIUM) == 16, + "size of StencilStrokePathCHROMIUM should be 16"); +static_assert(offsetof(StencilStrokePathCHROMIUM, header) == 0, + "offset of StencilStrokePathCHROMIUM header should be 0"); +static_assert(offsetof(StencilStrokePathCHROMIUM, path) == 4, + "offset of StencilStrokePathCHROMIUM path should be 4"); +static_assert(offsetof(StencilStrokePathCHROMIUM, reference) == 8, + "offset of StencilStrokePathCHROMIUM reference should be 8"); +static_assert(offsetof(StencilStrokePathCHROMIUM, mask) == 12, + "offset of StencilStrokePathCHROMIUM mask should be 12"); + +struct CoverFillPathCHROMIUM { + typedef CoverFillPathCHROMIUM ValueType; + static const CommandId kCmdId = kCoverFillPathCHROMIUM; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); + + static uint32_t ComputeSize() { + return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { header.SetCmd<ValueType>(); } + + void Init(GLuint _path, GLenum _coverMode) { + SetHeader(); + path = _path; + coverMode = _coverMode; + } + + void* Set(void* cmd, GLuint _path, GLenum _coverMode) { + static_cast<ValueType*>(cmd)->Init(_path, _coverMode); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32_t path; + uint32_t coverMode; +}; + +static_assert(sizeof(CoverFillPathCHROMIUM) == 12, + "size of CoverFillPathCHROMIUM should be 12"); +static_assert(offsetof(CoverFillPathCHROMIUM, header) == 0, + "offset of CoverFillPathCHROMIUM header should be 0"); +static_assert(offsetof(CoverFillPathCHROMIUM, path) == 4, + "offset of CoverFillPathCHROMIUM path should be 4"); +static_assert(offsetof(CoverFillPathCHROMIUM, coverMode) == 8, + "offset of CoverFillPathCHROMIUM coverMode should be 8"); + +struct CoverStrokePathCHROMIUM { + typedef CoverStrokePathCHROMIUM ValueType; + static const CommandId kCmdId = kCoverStrokePathCHROMIUM; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); + + static uint32_t ComputeSize() { + return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { header.SetCmd<ValueType>(); } + + void Init(GLuint _path, GLenum _coverMode) { + SetHeader(); + path = _path; + coverMode = _coverMode; + } + + void* Set(void* cmd, GLuint _path, GLenum _coverMode) { + static_cast<ValueType*>(cmd)->Init(_path, _coverMode); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32_t path; + uint32_t coverMode; +}; + +static_assert(sizeof(CoverStrokePathCHROMIUM) == 12, + "size of CoverStrokePathCHROMIUM should be 12"); +static_assert(offsetof(CoverStrokePathCHROMIUM, header) == 0, + "offset of CoverStrokePathCHROMIUM header should be 0"); +static_assert(offsetof(CoverStrokePathCHROMIUM, path) == 4, + "offset of CoverStrokePathCHROMIUM path should be 4"); +static_assert(offsetof(CoverStrokePathCHROMIUM, coverMode) == 8, + "offset of CoverStrokePathCHROMIUM coverMode should be 8"); + +struct StencilThenCoverFillPathCHROMIUM { + typedef StencilThenCoverFillPathCHROMIUM ValueType; + static const CommandId kCmdId = kStencilThenCoverFillPathCHROMIUM; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); + + static uint32_t ComputeSize() { + return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { header.SetCmd<ValueType>(); } + + void Init(GLuint _path, GLenum _fillMode, GLuint _mask, GLenum _coverMode) { + SetHeader(); + path = _path; + fillMode = _fillMode; + mask = _mask; + coverMode = _coverMode; + } + + void* Set(void* cmd, + GLuint _path, + GLenum _fillMode, + GLuint _mask, + GLenum _coverMode) { + static_cast<ValueType*>(cmd)->Init(_path, _fillMode, _mask, _coverMode); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32_t path; + uint32_t fillMode; + uint32_t mask; + uint32_t coverMode; +}; + +static_assert(sizeof(StencilThenCoverFillPathCHROMIUM) == 20, + "size of StencilThenCoverFillPathCHROMIUM should be 20"); +static_assert(offsetof(StencilThenCoverFillPathCHROMIUM, header) == 0, + "offset of StencilThenCoverFillPathCHROMIUM header should be 0"); +static_assert(offsetof(StencilThenCoverFillPathCHROMIUM, path) == 4, + "offset of StencilThenCoverFillPathCHROMIUM path should be 4"); +static_assert( + offsetof(StencilThenCoverFillPathCHROMIUM, fillMode) == 8, + "offset of StencilThenCoverFillPathCHROMIUM fillMode should be 8"); +static_assert(offsetof(StencilThenCoverFillPathCHROMIUM, mask) == 12, + "offset of StencilThenCoverFillPathCHROMIUM mask should be 12"); +static_assert( + offsetof(StencilThenCoverFillPathCHROMIUM, coverMode) == 16, + "offset of StencilThenCoverFillPathCHROMIUM coverMode should be 16"); + +struct StencilThenCoverStrokePathCHROMIUM { + typedef StencilThenCoverStrokePathCHROMIUM ValueType; + static const CommandId kCmdId = kStencilThenCoverStrokePathCHROMIUM; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); + + static uint32_t ComputeSize() { + return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { header.SetCmd<ValueType>(); } + + void Init(GLuint _path, GLint _reference, GLuint _mask, GLenum _coverMode) { + SetHeader(); + path = _path; + reference = _reference; + mask = _mask; + coverMode = _coverMode; + } + + void* Set(void* cmd, + GLuint _path, + GLint _reference, + GLuint _mask, + GLenum _coverMode) { + static_cast<ValueType*>(cmd)->Init(_path, _reference, _mask, _coverMode); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32_t path; + int32_t reference; + uint32_t mask; + uint32_t coverMode; +}; + +static_assert(sizeof(StencilThenCoverStrokePathCHROMIUM) == 20, + "size of StencilThenCoverStrokePathCHROMIUM should be 20"); +static_assert( + offsetof(StencilThenCoverStrokePathCHROMIUM, header) == 0, + "offset of StencilThenCoverStrokePathCHROMIUM header should be 0"); +static_assert(offsetof(StencilThenCoverStrokePathCHROMIUM, path) == 4, + "offset of StencilThenCoverStrokePathCHROMIUM path should be 4"); +static_assert( + offsetof(StencilThenCoverStrokePathCHROMIUM, reference) == 8, + "offset of StencilThenCoverStrokePathCHROMIUM reference should be 8"); +static_assert(offsetof(StencilThenCoverStrokePathCHROMIUM, mask) == 12, + "offset of StencilThenCoverStrokePathCHROMIUM mask should be 12"); +static_assert( + offsetof(StencilThenCoverStrokePathCHROMIUM, coverMode) == 16, + "offset of StencilThenCoverStrokePathCHROMIUM coverMode should be 16"); + struct BlendBarrierKHR { typedef BlendBarrierKHR ValueType; static const CommandId kCmdId = kBlendBarrierKHR; 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 cb4145a6..b6b81be 100644 --- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h @@ -4887,6 +4887,195 @@ TEST_F(GLES2FormatTest, MatrixLoadIdentityCHROMIUM) { CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); } +TEST_F(GLES2FormatTest, GenPathsCHROMIUM) { + cmds::GenPathsCHROMIUM& cmd = *GetBufferAs<cmds::GenPathsCHROMIUM>(); + void* next_cmd = + cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLsizei>(12)); + EXPECT_EQ(static_cast<uint32_t>(cmds::GenPathsCHROMIUM::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLuint>(11), cmd.first_client_id); + EXPECT_EQ(static_cast<GLsizei>(12), cmd.range); + CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); +} + +TEST_F(GLES2FormatTest, DeletePathsCHROMIUM) { + cmds::DeletePathsCHROMIUM& cmd = *GetBufferAs<cmds::DeletePathsCHROMIUM>(); + void* next_cmd = + cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLsizei>(12)); + EXPECT_EQ(static_cast<uint32_t>(cmds::DeletePathsCHROMIUM::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLuint>(11), cmd.first_client_id); + EXPECT_EQ(static_cast<GLsizei>(12), cmd.range); + CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); +} + +TEST_F(GLES2FormatTest, IsPathCHROMIUM) { + cmds::IsPathCHROMIUM& cmd = *GetBufferAs<cmds::IsPathCHROMIUM>(); + void* next_cmd = + cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<uint32_t>(12), + static_cast<uint32_t>(13)); + EXPECT_EQ(static_cast<uint32_t>(cmds::IsPathCHROMIUM::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLuint>(11), cmd.path); + EXPECT_EQ(static_cast<uint32_t>(12), cmd.result_shm_id); + EXPECT_EQ(static_cast<uint32_t>(13), cmd.result_shm_offset); + CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); +} + +TEST_F(GLES2FormatTest, PathCommandsCHROMIUM) { + cmds::PathCommandsCHROMIUM& cmd = *GetBufferAs<cmds::PathCommandsCHROMIUM>(); + void* next_cmd = + cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLsizei>(12), + static_cast<uint32_t>(13), static_cast<uint32_t>(14), + static_cast<GLsizei>(15), static_cast<GLenum>(16), + static_cast<uint32_t>(17), static_cast<uint32_t>(18)); + EXPECT_EQ(static_cast<uint32_t>(cmds::PathCommandsCHROMIUM::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLuint>(11), cmd.path); + EXPECT_EQ(static_cast<GLsizei>(12), cmd.numCommands); + EXPECT_EQ(static_cast<uint32_t>(13), cmd.commands_shm_id); + EXPECT_EQ(static_cast<uint32_t>(14), cmd.commands_shm_offset); + EXPECT_EQ(static_cast<GLsizei>(15), cmd.numCoords); + EXPECT_EQ(static_cast<GLenum>(16), cmd.coordType); + EXPECT_EQ(static_cast<uint32_t>(17), cmd.coords_shm_id); + EXPECT_EQ(static_cast<uint32_t>(18), cmd.coords_shm_offset); + CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); +} + +TEST_F(GLES2FormatTest, PathParameterfCHROMIUM) { + cmds::PathParameterfCHROMIUM& cmd = + *GetBufferAs<cmds::PathParameterfCHROMIUM>(); + void* next_cmd = cmd.Set(&cmd, static_cast<GLuint>(11), + static_cast<GLenum>(12), static_cast<GLfloat>(13)); + EXPECT_EQ(static_cast<uint32_t>(cmds::PathParameterfCHROMIUM::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLuint>(11), cmd.path); + EXPECT_EQ(static_cast<GLenum>(12), cmd.pname); + EXPECT_EQ(static_cast<GLfloat>(13), cmd.value); + CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); +} + +TEST_F(GLES2FormatTest, PathParameteriCHROMIUM) { + cmds::PathParameteriCHROMIUM& cmd = + *GetBufferAs<cmds::PathParameteriCHROMIUM>(); + void* next_cmd = cmd.Set(&cmd, static_cast<GLuint>(11), + static_cast<GLenum>(12), static_cast<GLint>(13)); + EXPECT_EQ(static_cast<uint32_t>(cmds::PathParameteriCHROMIUM::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLuint>(11), cmd.path); + EXPECT_EQ(static_cast<GLenum>(12), cmd.pname); + EXPECT_EQ(static_cast<GLint>(13), cmd.value); + CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); +} + +TEST_F(GLES2FormatTest, PathStencilFuncCHROMIUM) { + cmds::PathStencilFuncCHROMIUM& cmd = + *GetBufferAs<cmds::PathStencilFuncCHROMIUM>(); + void* next_cmd = cmd.Set(&cmd, static_cast<GLenum>(11), + static_cast<GLint>(12), static_cast<GLuint>(13)); + EXPECT_EQ(static_cast<uint32_t>(cmds::PathStencilFuncCHROMIUM::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLenum>(11), cmd.func); + EXPECT_EQ(static_cast<GLint>(12), cmd.ref); + EXPECT_EQ(static_cast<GLuint>(13), cmd.mask); + CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); +} + +TEST_F(GLES2FormatTest, StencilFillPathCHROMIUM) { + cmds::StencilFillPathCHROMIUM& cmd = + *GetBufferAs<cmds::StencilFillPathCHROMIUM>(); + void* next_cmd = cmd.Set(&cmd, static_cast<GLuint>(11), + static_cast<GLenum>(12), static_cast<GLuint>(13)); + EXPECT_EQ(static_cast<uint32_t>(cmds::StencilFillPathCHROMIUM::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLuint>(11), cmd.path); + EXPECT_EQ(static_cast<GLenum>(12), cmd.fillMode); + EXPECT_EQ(static_cast<GLuint>(13), cmd.mask); + CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); +} + +TEST_F(GLES2FormatTest, StencilStrokePathCHROMIUM) { + cmds::StencilStrokePathCHROMIUM& cmd = + *GetBufferAs<cmds::StencilStrokePathCHROMIUM>(); + void* next_cmd = cmd.Set(&cmd, static_cast<GLuint>(11), + static_cast<GLint>(12), static_cast<GLuint>(13)); + EXPECT_EQ(static_cast<uint32_t>(cmds::StencilStrokePathCHROMIUM::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLuint>(11), cmd.path); + EXPECT_EQ(static_cast<GLint>(12), cmd.reference); + EXPECT_EQ(static_cast<GLuint>(13), cmd.mask); + CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); +} + +TEST_F(GLES2FormatTest, CoverFillPathCHROMIUM) { + cmds::CoverFillPathCHROMIUM& cmd = + *GetBufferAs<cmds::CoverFillPathCHROMIUM>(); + void* next_cmd = + cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLenum>(12)); + EXPECT_EQ(static_cast<uint32_t>(cmds::CoverFillPathCHROMIUM::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLuint>(11), cmd.path); + EXPECT_EQ(static_cast<GLenum>(12), cmd.coverMode); + CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); +} + +TEST_F(GLES2FormatTest, CoverStrokePathCHROMIUM) { + cmds::CoverStrokePathCHROMIUM& cmd = + *GetBufferAs<cmds::CoverStrokePathCHROMIUM>(); + void* next_cmd = + cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLenum>(12)); + EXPECT_EQ(static_cast<uint32_t>(cmds::CoverStrokePathCHROMIUM::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLuint>(11), cmd.path); + EXPECT_EQ(static_cast<GLenum>(12), cmd.coverMode); + CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); +} + +TEST_F(GLES2FormatTest, StencilThenCoverFillPathCHROMIUM) { + cmds::StencilThenCoverFillPathCHROMIUM& cmd = + *GetBufferAs<cmds::StencilThenCoverFillPathCHROMIUM>(); + void* next_cmd = + cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLenum>(12), + static_cast<GLuint>(13), static_cast<GLenum>(14)); + EXPECT_EQ( + static_cast<uint32_t>(cmds::StencilThenCoverFillPathCHROMIUM::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLuint>(11), cmd.path); + EXPECT_EQ(static_cast<GLenum>(12), cmd.fillMode); + EXPECT_EQ(static_cast<GLuint>(13), cmd.mask); + EXPECT_EQ(static_cast<GLenum>(14), cmd.coverMode); + CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); +} + +TEST_F(GLES2FormatTest, StencilThenCoverStrokePathCHROMIUM) { + cmds::StencilThenCoverStrokePathCHROMIUM& cmd = + *GetBufferAs<cmds::StencilThenCoverStrokePathCHROMIUM>(); + void* next_cmd = + cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLint>(12), + static_cast<GLuint>(13), static_cast<GLenum>(14)); + EXPECT_EQ( + static_cast<uint32_t>(cmds::StencilThenCoverStrokePathCHROMIUM::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLuint>(11), cmd.path); + EXPECT_EQ(static_cast<GLint>(12), cmd.reference); + EXPECT_EQ(static_cast<GLuint>(13), cmd.mask); + EXPECT_EQ(static_cast<GLenum>(14), cmd.coverMode); + CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); +} + TEST_F(GLES2FormatTest, BlendBarrierKHR) { cmds::BlendBarrierKHR& cmd = *GetBufferAs<cmds::BlendBarrierKHR>(); void* next_cmd = cmd.Set(&cmd); diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h index 4a3a3d6..4661ac8 100644 --- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h @@ -302,7 +302,20 @@ OP(SwapInterval) /* 543 */ \ OP(MatrixLoadfCHROMIUMImmediate) /* 544 */ \ OP(MatrixLoadIdentityCHROMIUM) /* 545 */ \ - OP(BlendBarrierKHR) /* 546 */ + OP(GenPathsCHROMIUM) /* 546 */ \ + OP(DeletePathsCHROMIUM) /* 547 */ \ + OP(IsPathCHROMIUM) /* 548 */ \ + OP(PathCommandsCHROMIUM) /* 549 */ \ + OP(PathParameterfCHROMIUM) /* 550 */ \ + OP(PathParameteriCHROMIUM) /* 551 */ \ + OP(PathStencilFuncCHROMIUM) /* 552 */ \ + OP(StencilFillPathCHROMIUM) /* 553 */ \ + OP(StencilStrokePathCHROMIUM) /* 554 */ \ + OP(CoverFillPathCHROMIUM) /* 555 */ \ + OP(CoverStrokePathCHROMIUM) /* 556 */ \ + OP(StencilThenCoverFillPathCHROMIUM) /* 557 */ \ + OP(StencilThenCoverStrokePathCHROMIUM) /* 558 */ \ + OP(BlendBarrierKHR) /* 559 */ 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 7a33ab1..1471456 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils.cc +++ b/gpu/command_buffer/common/gles2_cmd_utils.cc @@ -702,6 +702,23 @@ size_t GLES2Util::GetGLTypeSizeForTexturesAndBuffers(uint32 type) { } } +size_t GLES2Util::GetGLTypeSizeForPathCoordType(uint32 type) { + switch (type) { + case GL_BYTE: + return sizeof(GLbyte); // NOLINT + case GL_UNSIGNED_BYTE: + return sizeof(GLubyte); // NOLINT + case GL_SHORT: + return sizeof(GLshort); // NOLINT + case GL_UNSIGNED_SHORT: + return sizeof(GLushort); // NOLINT + case GL_FLOAT: + return sizeof(GLfloat); // NOLINT + default: + return 0; + } +} + uint32 GLES2Util::GLErrorToErrorBit(uint32 error) { switch (error) { case GL_INVALID_ENUM: diff --git a/gpu/command_buffer/common/gles2_cmd_utils.h b/gpu/command_buffer/common/gles2_cmd_utils.h index 12b1551..4946205 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils.h +++ b/gpu/command_buffer/common/gles2_cmd_utils.h @@ -127,6 +127,8 @@ class GLES2_UTILS_EXPORT GLES2Util { static size_t GetGLTypeSizeForTexturesAndBuffers(uint32_t type); + static size_t GetGLTypeSizeForPathCoordType(uint32_t type); + static uint32_t GLErrorToErrorBit(uint32_t gl_error); static uint32_t GLErrorBitToGLError(uint32_t error_bit); diff --git a/gpu/command_buffer/common/gles2_cmd_utils_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_autogen.h index 6e3d161..0099155 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_utils_autogen.h @@ -46,6 +46,10 @@ static std::string GetStringInternalFormatParameter(uint32_t value); static std::string GetStringInvalidateFrameBufferTarget(uint32_t value); static std::string GetStringMapBufferAccess(uint32_t value); static std::string GetStringMatrixMode(uint32_t value); +static std::string GetStringPathCoordType(uint32_t value); +static std::string GetStringPathCoverMode(uint32_t value); +static std::string GetStringPathFillMode(uint32_t value); +static std::string GetStringPathParameter(uint32_t value); static std::string GetStringPixelStore(uint32_t value); static std::string GetStringPixelType(uint32_t value); static std::string GetStringProgramParameter(uint32_t value); 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 3dd31ca..6b061d4 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h @@ -141,6 +141,10 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { "GL_SHADER_BINARY_VIV", }, { + 0x90A7, + "GL_MITER_REVERT_CHROMIUM", + }, + { 0x9130, "GL_SGX_PROGRAM_BINARY_IMG", }, @@ -581,6 +585,10 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { "GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL", }, { + 0x90a4, + "GL_ROUND_CHROMIUM", + }, + { 0x8A48, "GL_TEXTURE_SRGB_DECODE_EXT", }, @@ -589,6 +597,10 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { "GL_CONTEXT_LOST", }, { + 0x90a3, + "GL_SQUARE_CHROMIUM", + }, + { 0x02000000, "GL_MULTISAMPLE_BUFFER_BIT1_QCOM", }, @@ -749,6 +761,10 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { "GL_RENDERBUFFER", }, { + 0x90B7, + "GL_PATH_STENCIL_FUNC_CHROMIUM", + }, + { 0x8A3A, "GL_UNIFORM_BLOCK_INDEX", }, @@ -761,10 +777,22 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { "GL_DITHER", }, { + 0x90B9, + "GL_PATH_STENCIL_VALUE_MASK_CHROMIUM", + }, + { + 0x90B8, + "GL_PATH_STENCIL_REF_CHROMIUM", + }, + { 0x93D3, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR", }, { + 0x1D00, + "GL_FLAT_CHROMIUM", + }, + { 0x9144, "GL_MAX_DEBUG_LOGGED_MESSAGES_KHR", }, @@ -981,6 +1009,10 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { "GL_UNSIGNED_INT_24_8_OES", }, { + 0x0A, + "GL_QUADRATIC_CURVE_TO_CHROMIUM", + }, + { 0x92D4, "GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS_EXT", }, @@ -1085,6 +1117,10 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { "GL_SAMPLE_COVERAGE", }, { + 0x0C, + "GL_CUBIC_CURVE_TO_CHROMIUM", + }, + { 0x928F, "GL_DST_ATOP_NV", }, @@ -1629,6 +1665,10 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { "GL_BGRA_EXT", }, { + 0x908B, + "GL_CONVEX_HULL_CHROMIUM", + }, + { 0x8ED7, "GL_COVERAGE_AUTOMATIC_NV", }, @@ -1889,6 +1929,10 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { "GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS_EXT", }, { + 0x04, + "GL_LINE_TO_CHROMIUM", + }, + { 0x0BE2, "GL_BLEND", }, @@ -1949,10 +1993,18 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { "GL_LINEARLIGHT_NV", }, { + 0x00, + "GL_CLOSE_PATH_CHROMIUM", + }, + { 0x8DCF, "GL_INT_SAMPLER_2D_ARRAY", }, { + 0x02, + "GL_MOVE_TO_CHROMIUM", + }, + { 0x886A, "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED", }, @@ -1961,10 +2013,22 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { "GL_SRGB8_NV", }, { + 0x9079, + "GL_PATH_JOIN_STYLE_CHROMIUM", + }, + { 0x0C01, "GL_DRAW_BUFFER_EXT", }, { + 0x9075, + "GL_PATH_STROKE_WIDTH_CHROMIUM", + }, + { + 0x9076, + "GL_PATH_END_CAPS_CHROMIUM", + }, + { 0x886C, "GL_MAX_TESS_CONTROL_INPUT_COMPONENTS_EXT", }, @@ -2477,8 +2541,8 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { "GL_TEXTURE10", }, { - 0x0BA7, - "GL_PATH_PROJECTION_MATRIX_CHROMIUM", + 0x78F1, + "GL_MAP_CHROMIUM", }, { 0x84CF, @@ -3057,6 +3121,10 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { "GL_TEXTURE4", }, { + 0x1A, + "GL_CONIC_CURVE_TO_CHROMIUM", + }, + { 0x821C, "GL_MINOR_VERSION", }, @@ -3261,6 +3329,10 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { "GL_UNSIGNED_INT_VEC3", }, { + 0x90A6, + "GL_BEVEL_CHROMIUM", + }, + { 0x1701, "GL_PATH_PROJECTION_CHROMIUM", }, @@ -3393,6 +3465,14 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { "GL_BUFFER_MAP_OFFSET", }, { + 0x9089, + "GL_COUNT_DOWN_CHROMIUM", + }, + { + 0x9088, + "GL_COUNT_UP_CHROMIUM", + }, + { 0x00004000, "GL_COLOR_BUFFER_BIT", }, @@ -3473,6 +3553,10 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { "GL_FENCE_STATUS_NV", }, { + 0x908D, + "GL_BOUNDING_BOX_CHROMIUM", + }, + { 0x88E6, "GL_STATIC_COPY", }, @@ -3589,6 +3673,10 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { "GL_UNIFORM_BUFFER_SIZE", }, { + 0x0BA7, + "GL_PATH_PROJECTION_MATRIX_CHROMIUM", + }, + { 0x0DE1, "GL_TEXTURE_2D", }, @@ -3677,6 +3765,10 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { "GL_R8UI", }, { + 0x90A4, + "GL_ROUND_CHROMIUM", + }, + { 0x150A, "GL_INVERT", }, @@ -4141,10 +4233,18 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { "GL_VERTEX_ATTRIB_ARRAY_SIZE", }, { + 0x9086, + "GL_PATH_STROKE_BOUND_CHROMIUM", + }, + { 0x8DB9, "GL_FRAMEBUFFER_SRGB_EXT", }, { + 0x907a, + "GL_PATH_MITER_LIMIT_CHROMIUM", + }, + { 0x9307, "GL_REFERENCED_BY_TESS_CONTROL_SHADER_EXT", }, @@ -4373,10 +4473,6 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { "GL_WRITEONLY_RENDERING_QCOM", }, { - 0x78F1, - "GL_MAP_CHROMIUM", - }, - { 0x8824, "GL_MAX_DRAW_BUFFERS_EXT", }, @@ -5034,6 +5130,49 @@ std::string GLES2Util::GetStringMatrixMode(uint32_t value) { arraysize(string_table), value); } +std::string GLES2Util::GetStringPathCoordType(uint32_t value) { + static const EnumToString string_table[] = { + {GL_BYTE, "GL_BYTE"}, + {GL_UNSIGNED_BYTE, "GL_UNSIGNED_BYTE"}, + {GL_SHORT, "GL_SHORT"}, + {GL_UNSIGNED_SHORT, "GL_UNSIGNED_SHORT"}, + {GL_FLOAT, "GL_FLOAT"}, + }; + return GLES2Util::GetQualifiedEnumString(string_table, + arraysize(string_table), value); +} + +std::string GLES2Util::GetStringPathCoverMode(uint32_t value) { + static const EnumToString string_table[] = { + {GL_CONVEX_HULL_CHROMIUM, "GL_CONVEX_HULL_CHROMIUM"}, + {GL_BOUNDING_BOX_CHROMIUM, "GL_BOUNDING_BOX_CHROMIUM"}, + }; + return GLES2Util::GetQualifiedEnumString(string_table, + arraysize(string_table), value); +} + +std::string GLES2Util::GetStringPathFillMode(uint32_t value) { + static const EnumToString string_table[] = { + {GL_INVERT, "GL_INVERT"}, + {GL_COUNT_UP_CHROMIUM, "GL_COUNT_UP_CHROMIUM"}, + {GL_COUNT_DOWN_CHROMIUM, "GL_COUNT_DOWN_CHROMIUM"}, + }; + return GLES2Util::GetQualifiedEnumString(string_table, + arraysize(string_table), value); +} + +std::string GLES2Util::GetStringPathParameter(uint32_t value) { + static const EnumToString string_table[] = { + {GL_PATH_STROKE_WIDTH_CHROMIUM, "GL_PATH_STROKE_WIDTH_CHROMIUM"}, + {GL_PATH_END_CAPS_CHROMIUM, "GL_PATH_END_CAPS_CHROMIUM"}, + {GL_PATH_JOIN_STYLE_CHROMIUM, "GL_PATH_JOIN_STYLE_CHROMIUM"}, + {GL_PATH_MITER_LIMIT_CHROMIUM, "GL_PATH_MITER_LIMIT_CHROMIUM"}, + {GL_PATH_STROKE_BOUND_CHROMIUM, "GL_PATH_STROKE_BOUND_CHROMIUM"}, + }; + return GLES2Util::GetQualifiedEnumString(string_table, + arraysize(string_table), value); +} + std::string GLES2Util::GetStringPixelStore(uint32_t value) { static const EnumToString string_table[] = { {GL_PACK_ALIGNMENT, "GL_PACK_ALIGNMENT"}, diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn index 14f2402..62fce76 100644 --- a/gpu/command_buffer/service/BUILD.gn +++ b/gpu/command_buffer/service/BUILD.gn @@ -100,6 +100,8 @@ source_set("service_sources") { "mailbox_manager_sync.h", "memory_program_cache.cc", "memory_program_cache.h", + "path_manager.cc", + "path_manager.h", "program_cache.cc", "program_cache.h", "program_manager.cc", diff --git a/gpu/command_buffer/service/context_group.cc b/gpu/command_buffer/service/context_group.cc index 4a82c56..1cc8f24 100644 --- a/gpu/command_buffer/service/context_group.cc +++ b/gpu/command_buffer/service/context_group.cc @@ -16,6 +16,7 @@ #include "gpu/command_buffer/service/gpu_switches.h" #include "gpu/command_buffer/service/mailbox_manager_impl.h" #include "gpu/command_buffer/service/memory_tracking.h" +#include "gpu/command_buffer/service/path_manager.h" #include "gpu/command_buffer/service/program_manager.h" #include "gpu/command_buffer/service/renderbuffer_manager.h" #include "gpu/command_buffer/service/shader_manager.h" @@ -294,6 +295,8 @@ bool ContextGroup::Initialize( feature_info_->workarounds().max_vertex_uniform_vectors)); } + path_manager_.reset(new PathManager()); + program_manager_.reset(new ProgramManager( program_cache_, max_varying_vectors_)); @@ -365,6 +368,11 @@ void ContextGroup::Destroy(GLES2Decoder* decoder, bool have_context) { texture_manager_.reset(); } + if (path_manager_ != NULL) { + path_manager_->Destroy(have_context); + path_manager_.reset(); + } + if (program_manager_ != NULL) { program_manager_->Destroy(have_context); program_manager_.reset(); diff --git a/gpu/command_buffer/service/context_group.h b/gpu/command_buffer/service/context_group.h index 466f918..32dbbf3 100644 --- a/gpu/command_buffer/service/context_group.h +++ b/gpu/command_buffer/service/context_group.h @@ -32,6 +32,7 @@ class GLES2Decoder; class FramebufferManager; class MailboxManager; class RenderbufferManager; +class PathManager; class ProgramManager; class ShaderManager; class TextureManager; @@ -153,6 +154,8 @@ class GPU_EXPORT ContextGroup : public base::RefCounted<ContextGroup> { return texture_manager_.get(); } + PathManager* path_manager() const { return path_manager_.get(); } + ProgramManager* program_manager() const { return program_manager_.get(); } @@ -291,6 +294,8 @@ class GPU_EXPORT ContextGroup : public base::RefCounted<ContextGroup> { scoped_ptr<TextureManager> texture_manager_; + scoped_ptr<PathManager> path_manager_; + scoped_ptr<ProgramManager> program_manager_; scoped_ptr<ShaderManager> shader_manager_; diff --git a/gpu/command_buffer/service/context_state_autogen.h b/gpu/command_buffer/service/context_state_autogen.h index e2b65bf..7ca2faa 100644 --- a/gpu/command_buffer/service/context_state_autogen.h +++ b/gpu/command_buffer/service/context_state_autogen.h @@ -74,6 +74,9 @@ GLenum hint_fragment_shader_derivative; GLfloat line_width; GLfloat modelview_matrix[16]; GLfloat projection_matrix[16]; +GLenum stencil_path_func; +GLint stencil_path_ref; +GLuint stencil_path_mask; GLint pack_alignment; GLint unpack_alignment; GLfloat polygon_offset_factor; diff --git a/gpu/command_buffer/service/context_state_impl_autogen.h b/gpu/command_buffer/service/context_state_impl_autogen.h index fa5462f..2dde530 100644 --- a/gpu/command_buffer/service/context_state_impl_autogen.h +++ b/gpu/command_buffer/service/context_state_impl_autogen.h @@ -104,6 +104,9 @@ void ContextState::Initialize() { projection_matrix[13] = 0.0f; projection_matrix[14] = 0.0f; projection_matrix[15] = 1.0f; + stencil_path_func = GL_ALWAYS; + stencil_path_ref = 0; + stencil_path_mask = 0xFFFFFFFFU; pack_alignment = 4; unpack_alignment = 4; polygon_offset_factor = 0.0f; @@ -276,6 +279,12 @@ void ContextState::InitState(const ContextState* prev_state) const { glMatrixLoadfEXT(GL_PATH_PROJECTION_CHROMIUM, projection_matrix); } } + if (feature_info_->feature_flags().chromium_path_rendering) + if ((stencil_path_func != prev_state->stencil_path_func) || + (stencil_path_ref != prev_state->stencil_path_ref) || + (stencil_path_mask != prev_state->stencil_path_mask)) + glPathStencilFuncNV(stencil_path_func, stencil_path_ref, + stencil_path_mask); if (prev_state->pack_alignment != pack_alignment) { glPixelStorei(GL_PACK_ALIGNMENT, pack_alignment); } @@ -355,6 +364,9 @@ void ContextState::InitState(const ContextState* prev_state) const { if (feature_info_->feature_flags().chromium_path_rendering) { glMatrixLoadfEXT(GL_PATH_PROJECTION_CHROMIUM, projection_matrix); } + if (feature_info_->feature_flags().chromium_path_rendering) + glPathStencilFuncNV(stencil_path_func, stencil_path_ref, + stencil_path_mask); glPixelStorei(GL_PACK_ALIGNMENT, pack_alignment); glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_alignment); glPolygonOffset(polygon_offset_factor, polygon_offset_units); @@ -547,6 +559,24 @@ bool ContextState::GetStateAsGLint(GLenum pname, } } return true; + case GL_PATH_STENCIL_FUNC_CHROMIUM: + *num_written = 1; + if (params) { + params[0] = static_cast<GLint>(stencil_path_func); + } + return true; + case GL_PATH_STENCIL_REF_CHROMIUM: + *num_written = 1; + if (params) { + params[0] = static_cast<GLint>(stencil_path_ref); + } + return true; + case GL_PATH_STENCIL_VALUE_MASK_CHROMIUM: + *num_written = 1; + if (params) { + params[0] = static_cast<GLint>(stencil_path_mask); + } + return true; case GL_PACK_ALIGNMENT: *num_written = 1; if (params) { @@ -897,6 +927,24 @@ bool ContextState::GetStateAsGLfloat(GLenum pname, memcpy(params, projection_matrix, sizeof(GLfloat) * 16); } return true; + case GL_PATH_STENCIL_FUNC_CHROMIUM: + *num_written = 1; + if (params) { + params[0] = static_cast<GLfloat>(stencil_path_func); + } + return true; + case GL_PATH_STENCIL_REF_CHROMIUM: + *num_written = 1; + if (params) { + params[0] = static_cast<GLfloat>(stencil_path_ref); + } + return true; + case GL_PATH_STENCIL_VALUE_MASK_CHROMIUM: + *num_written = 1; + if (params) { + params[0] = static_cast<GLfloat>(stencil_path_mask); + } + return true; case GL_PACK_ALIGNMENT: *num_written = 1; if (params) { diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc index 0ce9980..8caf05c 100644 --- a/gpu/command_buffer/service/feature_info.cc +++ b/gpu/command_buffer/service/feature_info.cc @@ -209,6 +209,9 @@ void FeatureInfo::InitializeBasicState(const base::CommandLine& command_line) { enable_unsafe_es3_apis_switch_ = command_line.HasSwitch(switches::kEnableUnsafeES3APIs); + enable_gl_path_rendering_switch_ = + command_line.HasSwitch(switches::kEnableGLPathRendering); + unsafe_es3_apis_enabled_ = false; } @@ -1004,14 +1007,18 @@ void FeatureInfo::InitializeFeatures() { } } - if (extensions.Contains("GL_NV_path_rendering")) { - if (extensions.Contains("GL_EXT_direct_state_access") || - gl_version_info_->is_es3) { - AddExtensionString("GL_CHROMIUM_path_rendering"); - feature_flags_.chromium_path_rendering = true; - validators_.g_l_state.AddValue(GL_PATH_MODELVIEW_MATRIX_CHROMIUM); - validators_.g_l_state.AddValue(GL_PATH_PROJECTION_MATRIX_CHROMIUM); - } + if (enable_gl_path_rendering_switch_ && + !workarounds_.disable_gl_path_rendering && + extensions.Contains("GL_NV_path_rendering") && + (extensions.Contains("GL_EXT_direct_state_access") || + gl_version_info_->is_es3)) { + AddExtensionString("GL_CHROMIUM_path_rendering"); + feature_flags_.chromium_path_rendering = true; + validators_.g_l_state.AddValue(GL_PATH_MODELVIEW_MATRIX_CHROMIUM); + validators_.g_l_state.AddValue(GL_PATH_PROJECTION_MATRIX_CHROMIUM); + validators_.g_l_state.AddValue(GL_PATH_STENCIL_FUNC_CHROMIUM); + validators_.g_l_state.AddValue(GL_PATH_STENCIL_REF_CHROMIUM); + validators_.g_l_state.AddValue(GL_PATH_STENCIL_VALUE_MASK_CHROMIUM); } if ((gl_version_info_->is_es3 || gl_version_info_->is_desktop_core_profile || diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h index 1ebff2a..aa9c0ba 100644 --- a/gpu/command_buffer/service/feature_info.h +++ b/gpu/command_buffer/service/feature_info.h @@ -164,6 +164,9 @@ class GPU_EXPORT FeatureInfo : public base::RefCounted<FeatureInfo> { bool unsafe_es3_apis_enabled_; + // Whether the command line switch kEnableGLPathRendering is passed in. + bool enable_gl_path_rendering_switch_; + scoped_ptr<gfx::GLVersionInfo> gl_version_info_; DISALLOW_COPY_AND_ASSIGN(FeatureInfo); diff --git a/gpu/command_buffer/service/feature_info_unittest.cc b/gpu/command_buffer/service/feature_info_unittest.cc index fdff175..8321e68 100644 --- a/gpu/command_buffer/service/feature_info_unittest.cc +++ b/gpu/command_buffer/service/feature_info_unittest.cc @@ -8,6 +8,7 @@ #include "base/memory/scoped_ptr.h" #include "base/strings/string_number_conversions.h" #include "gpu/command_buffer/service/gpu_service_test.h" +#include "gpu/command_buffer/service/gpu_switches.h" #include "gpu/command_buffer/service/test_helper.h" #include "gpu/command_buffer/service/texture_manager.h" #include "gpu/config/gpu_driver_bug_workaround_type.h" @@ -77,6 +78,18 @@ class FeatureInfoTest info_->Initialize(); } + void SetupInitExpectationsWithGLVersionAndCommandLine( + const char* extensions, + const char* renderer, + const char* version, + const base::CommandLine& command_line) { + GpuServiceTest::SetUpWithGLVersion(version, extensions); + TestHelper::SetupFeatureInfoInitExpectationsWithGLVersion( + gl_.get(), extensions, renderer, version); + info_ = new FeatureInfo(command_line); + info_->Initialize(); + } + void SetupWithCommandLine(const base::CommandLine& command_line) { GpuServiceTest::SetUp(); info_ = new FeatureInfo(command_line); @@ -1191,31 +1204,49 @@ TEST_P(FeatureInfoTest, BlendEquationAdvancedDisabled) { EXPECT_FALSE(info_->feature_flags().blend_equation_advanced_coherent); } -TEST_P(FeatureInfoTest, InitializeCHROMIUM_path_rendering) { +TEST_P(FeatureInfoTest, InitializeCHROMIUM_path_rendering_no_cmdline_switch) { SetupInitExpectationsWithGLVersion( "GL_ARB_compatibility GL_NV_path_rendering GL_EXT_direct_state_access", "", "4.3"); + EXPECT_FALSE(info_->feature_flags().chromium_path_rendering); + EXPECT_THAT(info_->extensions(), + Not(HasSubstr("GL_CHROMIUM_path_rendering"))); +} + +TEST_P(FeatureInfoTest, InitializeCHROMIUM_path_rendering) { + base::CommandLine command_line(0, NULL); + command_line.AppendSwitch(switches::kEnableGLPathRendering); + SetupInitExpectationsWithGLVersionAndCommandLine( + "GL_ARB_compatibility GL_NV_path_rendering GL_EXT_direct_state_access", + "", "4.3", command_line); EXPECT_TRUE(info_->feature_flags().chromium_path_rendering); EXPECT_THAT(info_->extensions(), HasSubstr("GL_CHROMIUM_path_rendering")); } TEST_P(FeatureInfoTest, InitializeCHROMIUM_path_rendering2) { - SetupInitExpectationsWithGLVersion( - "GL_NV_path_rendering", "", "OpenGL ES 3.1"); + base::CommandLine command_line(0, NULL); + command_line.AppendSwitch(switches::kEnableGLPathRendering); + SetupInitExpectationsWithGLVersionAndCommandLine( + "GL_NV_path_rendering", "", "OpenGL ES 3.1", command_line); EXPECT_TRUE(info_->feature_flags().chromium_path_rendering); EXPECT_THAT(info_->extensions(), HasSubstr("GL_CHROMIUM_path_rendering")); } TEST_P(FeatureInfoTest, InitializeNoCHROMIUM_path_rendering) { - SetupInitExpectationsWithGLVersion("GL_ARB_compatibility", "", "4.3"); + base::CommandLine command_line(0, NULL); + command_line.AppendSwitch(switches::kEnableGLPathRendering); + SetupInitExpectationsWithGLVersionAndCommandLine("GL_ARB_compatibility", "", + "4.3", command_line); EXPECT_FALSE(info_->feature_flags().chromium_path_rendering); EXPECT_THAT(info_->extensions(), Not(HasSubstr("GL_CHROMIUM_path_rendering"))); } TEST_P(FeatureInfoTest, InitializeNoCHROMIUM_path_rendering2) { - SetupInitExpectationsWithGLVersion( - "GL_ARB_compatibility GL_NV_path_rendering", "", "4.3"); + base::CommandLine command_line(0, NULL); + command_line.AppendSwitch(switches::kEnableGLPathRendering); + SetupInitExpectationsWithGLVersionAndCommandLine( + "GL_ARB_compatibility GL_NV_path_rendering", "", "4.3", command_line); EXPECT_FALSE(info_->feature_flags().chromium_path_rendering); EXPECT_THAT(info_->extensions(), Not(HasSubstr("GL_CHROMIUM_path_rendering"))); diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 4e35d55..3f70846 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -47,6 +47,7 @@ #include "gpu/command_buffer/service/logger.h" #include "gpu/command_buffer/service/mailbox_manager.h" #include "gpu/command_buffer/service/memory_tracking.h" +#include "gpu/command_buffer/service/path_manager.h" #include "gpu/command_buffer/service/program_manager.h" #include "gpu/command_buffer/service/query_manager.h" #include "gpu/command_buffer/service/renderbuffer_manager.h" @@ -791,6 +792,8 @@ class GLES2DecoderImpl : public GLES2Decoder, void DeleteQueriesEXTHelper(GLsizei n, const GLuint* client_ids); bool GenVertexArraysOESHelper(GLsizei n, const GLuint* client_ids); void DeleteVertexArraysOESHelper(GLsizei n, const GLuint* client_ids); + bool GenPathsCHROMIUMHelper(GLuint first_client_id, GLsizei range); + bool DeletePathsCHROMIUMHelper(GLuint first_client_id, GLsizei range); // Helper for async upload token completion notification callback. base::Closure AsyncUploadTokenCompletionClosure(uint32 async_upload_token, @@ -823,6 +826,8 @@ class GLES2DecoderImpl : public GLES2Decoder, return group_->valuebuffer_manager(); } + PathManager* path_manager() { return group_->path_manager(); } + ProgramManager* program_manager() { return group_->program_manager(); } @@ -1563,6 +1568,7 @@ class GLES2DecoderImpl : public GLES2Decoder, bool DoIsShader(GLuint client_id); bool DoIsTexture(GLuint client_id); bool DoIsVertexArrayOES(GLuint client_id); + bool DoIsPathCHROMIUM(GLuint client_id); // Wrapper for glLinkProgram void DoLinkProgram(GLuint program); @@ -3350,6 +3356,42 @@ bool GLES2DecoderImpl::GenTexturesHelper(GLsizei n, const GLuint* client_ids) { return true; } +bool GLES2DecoderImpl::GenPathsCHROMIUMHelper(GLuint first_client_id, + GLsizei range) { + GLuint last_client_id; + if (!SafeAddUint32(first_client_id, range - 1, &last_client_id)) + return false; + + if (path_manager()->HasPathsInRange(first_client_id, last_client_id)) + return false; + + GLuint first_service_id = glGenPathsNV(range); + if (first_service_id == 0) { + // We have to fail the connection here, because client has already + // succeeded in allocating the ids. This happens if we allocate + // the whole path id space (two allocations of 0x7FFFFFFF paths, for + // example). + return false; + } + // GenPathsNV does not wrap. + DCHECK(first_service_id + range - 1 >= first_service_id); + + path_manager()->CreatePathRange(first_client_id, last_client_id, + first_service_id); + + return true; +} + +bool GLES2DecoderImpl::DeletePathsCHROMIUMHelper(GLuint first_client_id, + GLsizei range) { + GLuint last_client_id; + if (!SafeAddUint32(first_client_id, range - 1, &last_client_id)) + return false; + + path_manager()->RemovePaths(first_client_id, last_client_id); + return true; +} + void GLES2DecoderImpl::DeleteBuffersHelper( GLsizei n, const GLuint* client_ids) { for (GLsizei ii = 0; ii < n; ++ii) { @@ -11748,6 +11790,12 @@ bool GLES2DecoderImpl::DoIsVertexArrayOES(GLuint client_id) { return vao && vao->IsValid() && !vao->IsDeleted(); } +bool GLES2DecoderImpl::DoIsPathCHROMIUM(GLuint client_id) { + GLuint service_id = 0; + return path_manager()->GetPath(client_id, &service_id) && + glIsPathNV(service_id) == GL_TRUE; +} + #if defined(OS_MACOSX) void GLES2DecoderImpl::ReleaseIOSurfaceForTexture(GLuint texture_id) { TextureToIOSurfaceMap::iterator it = texture_to_io_surface_map_.find( @@ -13833,6 +13881,455 @@ void GLES2DecoderImpl::OnOutOfMemoryError() { } } +error::Error GLES2DecoderImpl::HandleGenPathsCHROMIUM( + uint32 immediate_data_size, + const void* cmd_data) { + static const char kFunctionName[] = "glGenPathsCHROMIUM"; + const gles2::cmds::GenPathsCHROMIUM& c = + *static_cast<const gles2::cmds::GenPathsCHROMIUM*>(cmd_data); + if (!features().chromium_path_rendering) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, + "function not available"); + return error::kNoError; + } + + GLsizei range = static_cast<GLsizei>(c.range); + if (range < 0) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, kFunctionName, "range < 0"); + return error::kNoError; + } + + GLuint first_client_id = static_cast<GLuint>(c.first_client_id); + if (first_client_id == 0) + return error::kInvalidArguments; + + if (range == 0) + return error::kNoError; + + if (!GenPathsCHROMIUMHelper(first_client_id, range)) + return error::kInvalidArguments; + + return error::kNoError; +} +error::Error GLES2DecoderImpl::HandleDeletePathsCHROMIUM( + uint32_t immediate_data_size, + const void* cmd_data) { + static const char kFunctionName[] = "glDeletePathsCHROMIUM"; + const gles2::cmds::DeletePathsCHROMIUM& c = + *static_cast<const gles2::cmds::DeletePathsCHROMIUM*>(cmd_data); + if (!features().chromium_path_rendering) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, + "function not available"); + return error::kNoError; + } + + GLsizei range = static_cast<GLsizei>(c.range); + if (range < 0) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, kFunctionName, "range < 0"); + return error::kNoError; + } + + if (range == 0) + return error::kNoError; + + GLuint first_client_id = c.first_client_id; + // first_client_id can be 0, because non-existing path ids are skipped. + + if (!DeletePathsCHROMIUMHelper(first_client_id, range)) + return error::kInvalidArguments; + + return error::kNoError; +} + +error::Error GLES2DecoderImpl::HandlePathCommandsCHROMIUM( + uint32 immediate_data_size, + const void* cmd_data) { + static const char kFunctionName[] = "glPathCommandsCHROMIUM"; + const gles2::cmds::PathCommandsCHROMIUM& c = + *static_cast<const gles2::cmds::PathCommandsCHROMIUM*>(cmd_data); + if (!features().chromium_path_rendering) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, + "function not available"); + return error::kNoError; + } + + GLuint service_id = 0; + if (!path_manager()->GetPath(static_cast<GLuint>(c.path), &service_id)) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, + "invalid path name"); + return error::kNoError; + } + + GLsizei num_commands = static_cast<GLsizei>(c.numCommands); + if (num_commands < 0) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, kFunctionName, "numCommands < 0"); + return error::kNoError; + } + + GLsizei num_coords = static_cast<uint32>(c.numCoords); + if (num_coords < 0) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, kFunctionName, "numCoords < 0"); + return error::kNoError; + } + + GLenum coord_type = static_cast<uint32>(c.coordType); + if (!validators_->path_coord_type.IsValid(static_cast<GLint>(coord_type))) { + LOCAL_SET_GL_ERROR(GL_INVALID_ENUM, kFunctionName, "invalid coordType"); + return error::kNoError; + } + + const GLubyte* commands = NULL; + base::CheckedNumeric<GLsizei> num_coords_expected = 0; + + if (num_commands > 0) { + uint32 commands_shm_id = static_cast<uint32>(c.commands_shm_id); + uint32 commands_shm_offset = static_cast<uint32>(c.commands_shm_offset); + if (commands_shm_id != 0 || commands_shm_offset != 0) + commands = GetSharedMemoryAs<const GLubyte*>( + commands_shm_id, commands_shm_offset, num_commands); + + if (!commands) + return error::kOutOfBounds; + + for (GLsizei i = 0; i < num_commands; ++i) { + switch (commands[i]) { + case GL_CLOSE_PATH_CHROMIUM: + // Close has no coords. + break; + case GL_MOVE_TO_CHROMIUM: + // Fallthrough. + case GL_LINE_TO_CHROMIUM: + num_coords_expected += 2; + break; + case GL_QUADRATIC_CURVE_TO_CHROMIUM: + num_coords_expected += 4; + break; + case GL_CUBIC_CURVE_TO_CHROMIUM: + num_coords_expected += 6; + break; + case GL_CONIC_CURVE_TO_CHROMIUM: + num_coords_expected += 5; + break; + default: + LOCAL_SET_GL_ERROR(GL_INVALID_ENUM, kFunctionName, "invalid command"); + return error::kNoError; + } + } + } + + if (!num_coords_expected.IsValid() || + num_coords != num_coords_expected.ValueOrDie()) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, + "numCoords does not match commands"); + return error::kNoError; + } + + const void* coords = NULL; + + if (num_coords > 0) { + uint32 coords_size = 0; + uint32 coord_type_size = + GLES2Util::GetGLTypeSizeForPathCoordType(coord_type); + if (!SafeMultiplyUint32(num_coords, coord_type_size, &coords_size)) + return error::kOutOfBounds; + + uint32 coords_shm_id = static_cast<uint32>(c.coords_shm_id); + uint32 coords_shm_offset = static_cast<uint32>(c.coords_shm_offset); + if (coords_shm_id != 0 || coords_shm_offset != 0) + coords = GetSharedMemoryAs<const void*>(coords_shm_id, coords_shm_offset, + coords_size); + + if (!coords) + return error::kOutOfBounds; + } + + glPathCommandsNV(service_id, num_commands, commands, num_coords, coord_type, + coords); + + return error::kNoError; +} + +error::Error GLES2DecoderImpl::HandlePathParameterfCHROMIUM( + uint32 immediate_data_size, + const void* cmd_data) { + static const char kFunctionName[] = "glPathParameterfCHROMIUM"; + const gles2::cmds::PathParameterfCHROMIUM& c = + *static_cast<const gles2::cmds::PathParameterfCHROMIUM*>(cmd_data); + if (!features().chromium_path_rendering) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, + "function not available"); + return error::kNoError; + } + GLuint service_id = 0; + if (!path_manager()->GetPath(static_cast<GLuint>(c.path), &service_id)) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, + "invalid path name"); + return error::kNoError; + } + + GLenum pname = static_cast<GLenum>(c.pname); + GLfloat value = static_cast<GLfloat>(c.value); + bool hasValueError = false; + + switch (pname) { + case GL_PATH_STROKE_WIDTH_CHROMIUM: + case GL_PATH_MITER_LIMIT_CHROMIUM: + hasValueError = std::isnan(value) || !std::isfinite(value) || value < 0; + break; + case GL_PATH_STROKE_BOUND_CHROMIUM: + value = std::max(std::min(1.0f, value), 0.0f); + break; + case GL_PATH_END_CAPS_CHROMIUM: + hasValueError = !validators_->path_parameter_cap_values.IsValid( + static_cast<GLint>(value)); + break; + case GL_PATH_JOIN_STYLE_CHROMIUM: + hasValueError = !validators_->path_parameter_join_values.IsValid( + static_cast<GLint>(value)); + break; + default: + DCHECK(!validators_->path_parameter.IsValid(pname)); + LOCAL_SET_GL_ERROR_INVALID_ENUM(kFunctionName, pname, "pname"); + return error::kNoError; + } + DCHECK(validators_->path_parameter.IsValid(pname)); + + if (hasValueError) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, kFunctionName, "value not correct"); + return error::kNoError; + } + + glPathParameterfNV(service_id, pname, value); + return error::kNoError; +} + +error::Error GLES2DecoderImpl::HandlePathParameteriCHROMIUM( + uint32 immediate_data_size, + const void* cmd_data) { + static const char kFunctionName[] = "glPathParameteriCHROMIUM"; + const gles2::cmds::PathParameteriCHROMIUM& c = + *static_cast<const gles2::cmds::PathParameteriCHROMIUM*>(cmd_data); + if (!features().chromium_path_rendering) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, + "function not available"); + return error::kNoError; + } + GLuint service_id = 0; + if (!path_manager()->GetPath(static_cast<GLuint>(c.path), &service_id)) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, + "invalid path name"); + return error::kNoError; + } + + GLenum pname = static_cast<GLenum>(c.pname); + GLint value = static_cast<GLint>(c.value); + bool hasValueError = false; + + switch (pname) { + case GL_PATH_STROKE_WIDTH_CHROMIUM: + case GL_PATH_MITER_LIMIT_CHROMIUM: + hasValueError = value < 0; + break; + case GL_PATH_STROKE_BOUND_CHROMIUM: + value = std::max(std::min(1, value), 0); + break; + case GL_PATH_END_CAPS_CHROMIUM: + hasValueError = !validators_->path_parameter_cap_values.IsValid(value); + break; + case GL_PATH_JOIN_STYLE_CHROMIUM: + hasValueError = !validators_->path_parameter_join_values.IsValid(value); + break; + default: + DCHECK(!validators_->path_parameter.IsValid(pname)); + LOCAL_SET_GL_ERROR_INVALID_ENUM(kFunctionName, pname, "pname"); + return error::kNoError; + } + DCHECK(validators_->path_parameter.IsValid(pname)); + + if (hasValueError) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, kFunctionName, "value not correct"); + return error::kNoError; + } + + glPathParameteriNV(service_id, pname, value); + return error::kNoError; +} + +error::Error GLES2DecoderImpl::HandleStencilFillPathCHROMIUM( + uint32 immediate_data_size, + const void* cmd_data) { + static const char kFunctionName[] = "glStencilFillPathCHROMIUM"; + const gles2::cmds::StencilFillPathCHROMIUM& c = + *static_cast<const gles2::cmds::StencilFillPathCHROMIUM*>(cmd_data); + if (!features().chromium_path_rendering) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, + "function not available"); + return error::kNoError; + } + GLenum fill_mode = static_cast<GLenum>(c.fillMode); + if (!validators_->path_fill_mode.IsValid(fill_mode)) { + LOCAL_SET_GL_ERROR_INVALID_ENUM(kFunctionName, fill_mode, "fillMode"); + return error::kNoError; + } + GLuint mask = static_cast<GLuint>(c.mask); + if ((fill_mode == GL_COUNT_UP_CHROMIUM || + fill_mode == GL_COUNT_DOWN_CHROMIUM) && + GLES2Util::IsNPOT(mask + 1)) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, kFunctionName, + "mask + 1 is not power of two"); + return error::kNoError; + } + GLuint service_id = 0; + if (!path_manager()->GetPath(static_cast<GLuint>(c.path), &service_id)) { + // "If /path/ does not name an existing path object, the command does + // nothing (and no error is generated)." + // This holds for other rendering functions, too. + return error::kNoError; + } + ApplyDirtyState(); + glStencilFillPathNV(service_id, fill_mode, mask); + return error::kNoError; +} + +error::Error GLES2DecoderImpl::HandleStencilStrokePathCHROMIUM( + uint32 immediate_data_size, + const void* cmd_data) { + static const char kFunctionName[] = "glStencilStrokePathCHROMIUM"; + const gles2::cmds::StencilStrokePathCHROMIUM& c = + *static_cast<const gles2::cmds::StencilStrokePathCHROMIUM*>(cmd_data); + if (!features().chromium_path_rendering) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, + "function not available"); + return error::kNoError; + } + GLuint service_id = 0; + if (!path_manager()->GetPath(static_cast<GLuint>(c.path), &service_id)) { + return error::kNoError; + } + GLint reference = static_cast<GLint>(c.reference); + GLuint mask = static_cast<GLuint>(c.mask); + ApplyDirtyState(); + glStencilStrokePathNV(service_id, reference, mask); + return error::kNoError; +} + +error::Error GLES2DecoderImpl::HandleCoverFillPathCHROMIUM( + uint32 immediate_data_size, + const void* cmd_data) { + static const char kFunctionName[] = "glCoverFillPathCHROMIUM"; + const gles2::cmds::CoverFillPathCHROMIUM& c = + *static_cast<const gles2::cmds::CoverFillPathCHROMIUM*>(cmd_data); + if (!features().chromium_path_rendering) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, + "function not available"); + return error::kNoError; + } + GLenum cover_mode = static_cast<GLenum>(c.coverMode); + if (!validators_->path_cover_mode.IsValid(cover_mode)) { + LOCAL_SET_GL_ERROR_INVALID_ENUM(kFunctionName, cover_mode, "coverMode"); + return error::kNoError; + } + GLuint service_id = 0; + if (!path_manager()->GetPath(static_cast<GLuint>(c.path), &service_id)) + return error::kNoError; + + ApplyDirtyState(); + glCoverFillPathNV(service_id, cover_mode); + return error::kNoError; +} + +error::Error GLES2DecoderImpl::HandleCoverStrokePathCHROMIUM( + uint32 immediate_data_size, + const void* cmd_data) { + static const char kFunctionName[] = "glCoverStrokePathCHROMIUM"; + const gles2::cmds::CoverStrokePathCHROMIUM& c = + *static_cast<const gles2::cmds::CoverStrokePathCHROMIUM*>(cmd_data); + if (!features().chromium_path_rendering) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, + "function not available"); + return error::kNoError; + } + GLenum cover_mode = static_cast<GLenum>(c.coverMode); + if (!validators_->path_cover_mode.IsValid(cover_mode)) { + LOCAL_SET_GL_ERROR_INVALID_ENUM(kFunctionName, cover_mode, "coverMode"); + return error::kNoError; + } + GLuint service_id = 0; + if (!path_manager()->GetPath(static_cast<GLuint>(c.path), &service_id)) + return error::kNoError; + + ApplyDirtyState(); + glCoverStrokePathNV(service_id, cover_mode); + return error::kNoError; +} + +error::Error GLES2DecoderImpl::HandleStencilThenCoverFillPathCHROMIUM( + uint32 immediate_data_size, + const void* cmd_data) { + static const char kFunctionName[] = "glStencilThenCoverFillPathCHROMIUM"; + const gles2::cmds::StencilThenCoverFillPathCHROMIUM& c = + *static_cast<const gles2::cmds::StencilThenCoverFillPathCHROMIUM*>( + cmd_data); + if (!features().chromium_path_rendering) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, + "function not available"); + return error::kNoError; + } + GLenum fill_mode = static_cast<GLenum>(c.fillMode); + if (!validators_->path_fill_mode.IsValid(fill_mode)) { + LOCAL_SET_GL_ERROR_INVALID_ENUM(kFunctionName, fill_mode, "fillMode"); + return error::kNoError; + } + GLuint mask = static_cast<GLuint>(c.mask); + if ((fill_mode == GL_COUNT_UP_CHROMIUM || + fill_mode == GL_COUNT_DOWN_CHROMIUM) && + GLES2Util::IsNPOT(mask + 1)) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, kFunctionName, + "mask + 1 is not power of two"); + return error::kNoError; + } + GLenum cover_mode = static_cast<GLenum>(c.coverMode); + if (!validators_->path_cover_mode.IsValid(cover_mode)) { + LOCAL_SET_GL_ERROR_INVALID_ENUM(kFunctionName, cover_mode, "coverMode"); + return error::kNoError; + } + GLuint service_id = 0; + if (!path_manager()->GetPath(static_cast<GLuint>(c.path), &service_id)) + return error::kNoError; + + ApplyDirtyState(); + glStencilThenCoverFillPathNV(service_id, fill_mode, mask, cover_mode); + return error::kNoError; +} + +error::Error GLES2DecoderImpl::HandleStencilThenCoverStrokePathCHROMIUM( + uint32 immediate_data_size, + const void* cmd_data) { + static const char kFunctionName[] = "glStencilThenCoverStrokePathCHROMIUM"; + const gles2::cmds::StencilThenCoverStrokePathCHROMIUM& c = + *static_cast<const gles2::cmds::StencilThenCoverStrokePathCHROMIUM*>( + cmd_data); + if (!features().chromium_path_rendering) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, + "function not available"); + return error::kNoError; + } + GLenum cover_mode = static_cast<GLenum>(c.coverMode); + if (!validators_->path_cover_mode.IsValid(cover_mode)) { + LOCAL_SET_GL_ERROR_INVALID_ENUM(kFunctionName, cover_mode, "coverMode"); + return error::kNoError; + } + GLuint service_id = 0; + if (!path_manager()->GetPath(static_cast<GLuint>(c.path), &service_id)) + return error::kNoError; + + GLint reference = static_cast<GLint>(c.reference); + GLuint mask = static_cast<GLuint>(c.mask); + ApplyDirtyState(); + glStencilThenCoverStrokePathNV(service_id, reference, mask, cover_mode); + return error::kNoError; +} + // 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 1314d0d..615d287 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h @@ -4946,6 +4946,58 @@ error::Error GLES2DecoderImpl::HandleMatrixLoadIdentityCHROMIUM( return error::kNoError; } +error::Error GLES2DecoderImpl::HandleIsPathCHROMIUM( + uint32_t immediate_data_size, + const void* cmd_data) { + const gles2::cmds::IsPathCHROMIUM& c = + *static_cast<const gles2::cmds::IsPathCHROMIUM*>(cmd_data); + (void)c; + if (!features().chromium_path_rendering) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glIsPathCHROMIUM", + "function not available"); + return error::kNoError; + } + + GLuint path = c.path; + typedef cmds::IsPathCHROMIUM::Result Result; + Result* result_dst = GetSharedMemoryAs<Result*>( + c.result_shm_id, c.result_shm_offset, sizeof(*result_dst)); + if (!result_dst) { + return error::kOutOfBounds; + } + *result_dst = DoIsPathCHROMIUM(path); + return error::kNoError; +} + +error::Error GLES2DecoderImpl::HandlePathStencilFuncCHROMIUM( + uint32_t immediate_data_size, + const void* cmd_data) { + const gles2::cmds::PathStencilFuncCHROMIUM& c = + *static_cast<const gles2::cmds::PathStencilFuncCHROMIUM*>(cmd_data); + (void)c; + if (!features().chromium_path_rendering) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glPathStencilFuncCHROMIUM", + "function not available"); + return error::kNoError; + } + + GLenum func = static_cast<GLenum>(c.func); + GLint ref = static_cast<GLint>(c.ref); + GLuint mask = static_cast<GLuint>(c.mask); + if (!validators_->cmp_function.IsValid(func)) { + LOCAL_SET_GL_ERROR_INVALID_ENUM("glPathStencilFuncCHROMIUM", func, "func"); + return error::kNoError; + } + if (state_.stencil_path_func != func || state_.stencil_path_ref != ref || + state_.stencil_path_mask != mask) { + state_.stencil_path_func = func; + state_.stencil_path_ref = ref; + state_.stencil_path_mask = mask; + glPathStencilFuncNV(func, ref, mask); + } + return error::kNoError; +} + error::Error GLES2DecoderImpl::HandleBlendBarrierKHR( uint32_t immediate_data_size, const void* cmd_data) { diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h index 1620423..dd11716 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h @@ -71,6 +71,11 @@ void GLES2DecoderTestBase::SetupInitStateExpectations() { .Times(1) .RetiresOnSaturation(); } + if (group_->feature_info()->feature_flags().chromium_path_rendering) { + EXPECT_CALL(*gl_, PathStencilFuncNV(GL_ALWAYS, 0, 0xFFFFFFFFU)) + .Times(1) + .RetiresOnSaturation(); + } EXPECT_CALL(*gl_, PixelStorei(GL_PACK_ALIGNMENT, 4)) .Times(1) .RetiresOnSaturation(); diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_4_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_4_autogen.h new file mode 100644 index 0000000..9abba52 --- /dev/null +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_4_autogen.h @@ -0,0 +1,15 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file is auto-generated from +// gpu/command_buffer/build_gles2_cmd_buffer.py +// It's formatted by clang-format using chromium coding style: +// clang-format -i -style=chromium filename +// DO NOT EDIT! + +// It is included by gles2_cmd_decoder_unittest_4.cc +#ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_4_AUTOGEN_H_ +#define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_4_AUTOGEN_H_ + +#endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_4_AUTOGEN_H_ diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc index f87a4bd..916f2aa 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc @@ -4,21 +4,134 @@ #include "gpu/command_buffer/service/gles2_cmd_decoder.h" +#include "base/command_line.h" #include "gpu/command_buffer/common/gles2_cmd_format.h" #include "gpu/command_buffer/common/gles2_cmd_utils.h" #include "gpu/command_buffer/service/gles2_cmd_decoder_unittest.h" +#include "gpu/command_buffer/service/gpu_switches.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gl/gl_mock.h" using ::gfx::MockGLInterface; using ::testing::_; +using ::testing::Return; namespace gpu { namespace gles2 { +// Class to use to test that functions which need feature flags or +// extensions always return INVALID_OPERATION if the feature flags is not +// enabled or extension is not present. +class GLES2DecoderTestDisabledExtensions : public GLES2DecoderTest { + public: + GLES2DecoderTestDisabledExtensions() {} +}; +INSTANTIATE_TEST_CASE_P(Service, + GLES2DecoderTestDisabledExtensions, + ::testing::Bool()); + +TEST_P(GLES2DecoderTestDisabledExtensions, CHROMIUMPathRenderingDisabled) { + const GLuint kClientPathId = 0; + { + cmds::MatrixLoadfCHROMIUMImmediate& cmd = + *GetImmediateAs<cmds::MatrixLoadfCHROMIUMImmediate>(); + GLfloat temp[16] = { + 0, + }; + cmd.Init(GL_PATH_MODELVIEW_CHROMIUM, temp); + EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(temp))); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + } + { + cmds::MatrixLoadIdentityCHROMIUM cmd; + cmd.Init(GL_PATH_PROJECTION_CHROMIUM); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + } + { + cmds::GenPathsCHROMIUM cmd; + cmd.Init(0, 0); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + } + { + cmds::DeletePathsCHROMIUM cmd; + cmd.Init(0, 0); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + } + { + cmds::IsPathCHROMIUM cmd; + cmd.Init(kClientPathId, shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + } + { + cmds::PathCommandsCHROMIUM cmd; + cmd.Init(kClientPathId, 0, 0, 0, 0, GL_FLOAT, 0, 0); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + } + { + cmds::PathParameterfCHROMIUM cmd; + cmd.Init(kClientPathId, GL_PATH_STROKE_WIDTH_CHROMIUM, 1.0f); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + } + { + cmds::PathParameteriCHROMIUM cmd; + cmd.Init(kClientPathId, GL_PATH_STROKE_WIDTH_CHROMIUM, 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + } + { + cmds::PathStencilFuncCHROMIUM cmd; + cmd.Init(GL_NEVER, 2, 3); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + } + { + cmds::StencilFillPathCHROMIUM cmd; + cmd.Init(kClientPathId, GL_COUNT_UP_CHROMIUM, 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + } + { + cmds::StencilStrokePathCHROMIUM cmd; + cmd.Init(kClientPathId, 1, 2); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + } + { + cmds::CoverFillPathCHROMIUM cmd; + cmd.Init(kClientPathId, GL_BOUNDING_BOX_CHROMIUM); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + } + { + cmds::CoverStrokePathCHROMIUM cmd; + cmd.Init(kClientPathId, GL_BOUNDING_BOX_CHROMIUM); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + } + { + cmds::StencilThenCoverFillPathCHROMIUM cmd; + cmd.Init(kClientPathId, GL_COUNT_UP_CHROMIUM, 1, GL_BOUNDING_BOX_CHROMIUM); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + } + { + cmds::StencilThenCoverStrokePathCHROMIUM cmd; + cmd.Init(kClientPathId, 1, 2, GL_BOUNDING_BOX_CHROMIUM); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + } +} + class GLES2DecoderTestWithCHROMIUMPathRendering : public GLES2DecoderTest { public: - GLES2DecoderTestWithCHROMIUMPathRendering() {} + GLES2DecoderTestWithCHROMIUMPathRendering() : client_path_id_(125) {} + void SetUp() override { InitState init; init.gl_version = "opengl es 3.1"; @@ -28,8 +141,24 @@ class GLES2DecoderTestWithCHROMIUMPathRendering : public GLES2DecoderTest { init.request_depth = true; init.bind_generates_resource = true; init.extensions = "GL_NV_path_rendering"; - InitDecoder(init); + base::CommandLine command_line(0, NULL); + command_line.AppendSwitch(switches::kEnableGLPathRendering); + InitDecoderWithCommandLine(init, &command_line); + + EXPECT_CALL(*gl_, GenPathsNV(1)) + .WillOnce(Return(kServicePathId)) + .RetiresOnSaturation(); + cmds::GenPathsCHROMIUM cmd; + cmd.Init(client_path_id_, 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); } + + protected: + template <typename TypeParam> + void TestPathCommandsCHROMIUMCoordTypes(); + + GLuint client_path_id_; + static const GLuint kServicePathId = 311; }; INSTANTIATE_TEST_CASE_P(Service, @@ -56,6 +185,814 @@ INSTANTIATE_TEST_CASE_P(Service, GLES2DecoderTestWithBlendEquationAdvanced, ::testing::Bool()); +TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, GenDeletePaths) { + static GLuint kFirstClientID = client_path_id_ + 88; + static GLsizei kPathCount = 58; + static GLuint kFirstCreatedServiceID = 8000; + + // GenPaths range 0 causes no calls. + cmds::GenPathsCHROMIUM gen_cmd; + gen_cmd.Init(kFirstClientID, 0); + EXPECT_EQ(error::kNoError, ExecuteCmd(gen_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + // DeletePaths range 0 causes no calls. + cmds::DeletePathsCHROMIUM delete_cmd; + delete_cmd.Init(kFirstClientID, 0); + EXPECT_EQ(error::kNoError, ExecuteCmd(delete_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + // DeletePaths client 0 causes no calls and no errors. + delete_cmd.Init(0, 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(delete_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + // DeletePaths with a big range should not cause any deletes. + delete_cmd.Init(client_path_id_ + 1, + std::numeric_limits<GLsizei>::max() - client_path_id_ - 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(delete_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + delete_cmd.Init(std::numeric_limits<GLsizei>::max() + 1, + std::numeric_limits<GLsizei>::max()); + EXPECT_EQ(error::kNoError, ExecuteCmd(delete_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + // Normal Gen and Delete should cause the normal calls. + EXPECT_CALL(*gl_, GenPathsNV(kPathCount)) + .WillOnce(Return(kFirstCreatedServiceID)) + .RetiresOnSaturation(); + + gen_cmd.Init(kFirstClientID, kPathCount); + EXPECT_EQ(error::kNoError, ExecuteCmd(gen_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + EXPECT_CALL(*gl_, DeletePathsNV(kFirstCreatedServiceID, kPathCount)) + .RetiresOnSaturation(); + + delete_cmd.Init(kFirstClientID, kPathCount); + EXPECT_EQ(error::kNoError, ExecuteCmd(delete_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, GenDeleteRanges) { + static GLuint kFirstClientID = client_path_id_ + 77; + static GLsizei kPathCount = 5800; + static GLuint kFirstCreatedServiceID = 8000; + + // Create a range of path names, delete one in middle and then + // the rest. Expect 3 DeletePath calls. + EXPECT_CALL(*gl_, GenPathsNV(kPathCount)) + .WillOnce(Return(kFirstCreatedServiceID)) + .RetiresOnSaturation(); + cmds::GenPathsCHROMIUM gen_cmd; + gen_cmd.Init(kFirstClientID, kPathCount); + EXPECT_EQ(error::kNoError, ExecuteCmd(gen_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + EXPECT_CALL(*gl_, DeletePathsNV(kFirstCreatedServiceID + (kPathCount / 2), 1)) + .RetiresOnSaturation(); + + cmds::DeletePathsCHROMIUM delete_cmd; + delete_cmd.Init(kFirstClientID + (kPathCount / 2), 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(delete_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + EXPECT_CALL(*gl_, DeletePathsNV(kFirstCreatedServiceID, (kPathCount / 2))) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, DeletePathsNV(kFirstCreatedServiceID + (kPathCount / 2) + 1, + (kPathCount / 2) - 1)).RetiresOnSaturation(); + + delete_cmd.Init(kFirstClientID, kPathCount); + EXPECT_EQ(error::kNoError, ExecuteCmd(delete_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, GenDeleteManyPaths) { + static GLuint kFirstClientID = client_path_id_ + 1; + static GLsizei kPathCount = std::numeric_limits<GLsizei>::max(); + static GLuint kFirstCreatedServiceID = 8000; + + EXPECT_CALL(*gl_, GenPathsNV(kPathCount)) + .WillOnce(Return(kFirstCreatedServiceID)) + .RetiresOnSaturation(); + + // GenPaths with big range. + cmds::GenPathsCHROMIUM gen_cmd; + gen_cmd.Init(kFirstClientID, kPathCount); + EXPECT_EQ(error::kNoError, ExecuteCmd(gen_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + // Path range wraps, so we get connection error. + gen_cmd.Init(kFirstClientID + kPathCount, kPathCount); + EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(gen_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + EXPECT_CALL(*gl_, DeletePathsNV(kFirstCreatedServiceID, kPathCount)) + .RetiresOnSaturation(); + + cmds::DeletePathsCHROMIUM delete_cmd; + delete_cmd.Init(kFirstClientID, kPathCount); + EXPECT_EQ(error::kNoError, ExecuteCmd(delete_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + // Delete every possible path. + // We run into the one created for client_path_id_. + EXPECT_CALL(*gl_, DeletePathsNV(kServicePathId, 1)).RetiresOnSaturation(); + + delete_cmd.Init(1u, kPathCount); + EXPECT_EQ(error::kNoError, ExecuteCmd(delete_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + delete_cmd.Init(static_cast<GLuint>(kPathCount) + 1u, kPathCount); + EXPECT_EQ(error::kNoError, ExecuteCmd(delete_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + // Allocate every possible path, delete few, allocate them back and + // expect minimum amount of calls. + EXPECT_CALL(*gl_, GenPathsNV(kPathCount)) + .WillOnce(Return(static_cast<GLuint>(1u))) + .WillOnce(Return(static_cast<GLuint>(kPathCount) + 1u)) + .RetiresOnSaturation(); + + gen_cmd.Init(1u, kPathCount); + EXPECT_EQ(error::kNoError, ExecuteCmd(gen_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + gen_cmd.Init(static_cast<GLuint>(kPathCount) + 1u, kPathCount); + EXPECT_EQ(error::kNoError, ExecuteCmd(gen_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + gen_cmd.Init(static_cast<GLuint>(kPathCount) * 2u + 2u, kPathCount); + EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(gen_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + EXPECT_CALL(*gl_, DeletePathsNV(kFirstClientID, 4)).RetiresOnSaturation(); + + delete_cmd.Init(kFirstClientID, 4); + EXPECT_EQ(error::kNoError, ExecuteCmd(delete_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + EXPECT_CALL(*gl_, DeletePathsNV(kFirstClientID * 3, 1)).RetiresOnSaturation(); + + delete_cmd.Init(kFirstClientID * 3, 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(delete_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + EXPECT_CALL(*gl_, GenPathsNV(1)) + .WillOnce(Return(kFirstClientID)) + .WillOnce(Return(kFirstClientID + 1)) + .WillOnce(Return(kFirstClientID + 2)) + .WillOnce(Return(kFirstClientID + 3)) + .RetiresOnSaturation(); + + for (int i = 0; i < 4; ++i) { + gen_cmd.Init(kFirstClientID + i, 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(gen_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + } + + EXPECT_CALL(*gl_, GenPathsNV(1)) + .WillOnce(Return(kFirstClientID * 3)) + .RetiresOnSaturation(); + gen_cmd.Init(kFirstClientID * 3, 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(gen_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + EXPECT_CALL(*gl_, DeletePathsNV(1u, kPathCount)).RetiresOnSaturation(); + EXPECT_CALL(*gl_, DeletePathsNV(static_cast<GLuint>(kPathCount) + 1u, + kPathCount)).RetiresOnSaturation(); + + delete_cmd.Init(1u, kPathCount); + EXPECT_EQ(error::kNoError, ExecuteCmd(delete_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + delete_cmd.Init(static_cast<GLuint>(kPathCount) + 1u, kPathCount); + EXPECT_EQ(error::kNoError, ExecuteCmd(delete_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + // Cleanup: return the client_path_id_ as a path. + EXPECT_CALL(*gl_, GenPathsNV(1)) + .WillOnce(Return(static_cast<GLuint>(kServicePathId))) + .RetiresOnSaturation(); + + gen_cmd.Init(client_path_id_, 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(gen_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, + GenPathsCHROMIUMInvalidCalls) { + static GLuint kFirstClientID = client_path_id_ + 88; + static GLsizei kPathCount = 5800; + static GLuint kFirstCreatedServiceID = 8000; + + // Range < 0 is causes gl error. + cmds::GenPathsCHROMIUM gen_cmd; + gen_cmd.Init(kFirstClientID, -1); + EXPECT_EQ(error::kNoError, ExecuteCmd(gen_cmd)); + EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); + + // Path 0 is invalid client id, connection error. + gen_cmd.Init(0, kPathCount); + EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(gen_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + // Too big range causes client id to wrap, connection error. + gen_cmd.Init(std::numeric_limits<GLsizei>::max() + 3, + std::numeric_limits<GLsizei>::max()); + EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(gen_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + // Creating duplicate client_ids cause connection error. + EXPECT_CALL(*gl_, GenPathsNV(kPathCount)) + .WillOnce(Return(kFirstCreatedServiceID)) + .RetiresOnSaturation(); + + gen_cmd.Init(kFirstClientID, kPathCount); + EXPECT_EQ(error::kNoError, ExecuteCmd(gen_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + // Create duplicate by executing the same cmd. + EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(gen_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + // Create duplicate by creating a range that contains + // an already existing client path id. + gen_cmd.Init(kFirstClientID - 1, 2); + EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(gen_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + // Cleanup. + EXPECT_CALL(*gl_, DeletePathsNV(kFirstCreatedServiceID, kPathCount)) + .RetiresOnSaturation(); + cmds::DeletePathsCHROMIUM delete_cmd; + delete_cmd.Init(kFirstClientID, kPathCount); + EXPECT_EQ(error::kNoError, ExecuteCmd(delete_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, + DeletePathsCHROMIUMInvalidCalls) { + static GLuint kFirstClientID = client_path_id_ + 88; + + // Range < 0 is causes gl error. + cmds::DeletePathsCHROMIUM delete_cmd; + delete_cmd.Init(kFirstClientID, -1); + EXPECT_EQ(error::kNoError, ExecuteCmd(delete_cmd)); + EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); + + // Too big range causes client id to wrap, connection error. + delete_cmd.Init(std::numeric_limits<GLsizei>::max() + 3, + std::numeric_limits<GLsizei>::max()); + EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(delete_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, + PathCommandsCHROMIUMInvalidCalls) { + static const GLsizei kCorrectCoordCount = 19; + static const GLsizei kCorrectCommandCount = 6; + static const GLenum kInvalidCoordType = GL_NONE; + + GLfloat* coords = GetSharedMemoryAs<GLfloat*>(); + unsigned commands_offset = sizeof(GLfloat) * kCorrectCoordCount; + GLubyte* commands = GetSharedMemoryAsWithOffset<GLubyte*>(commands_offset); + for (int i = 0; i < kCorrectCoordCount; ++i) { + coords[i] = 5.0f * i; + } + commands[0] = GL_MOVE_TO_CHROMIUM; + commands[1] = GL_CLOSE_PATH_CHROMIUM; + commands[2] = GL_LINE_TO_CHROMIUM; + commands[3] = GL_QUADRATIC_CURVE_TO_CHROMIUM; + commands[4] = GL_CUBIC_CURVE_TO_CHROMIUM; + commands[5] = GL_CONIC_CURVE_TO_CHROMIUM; + + EXPECT_CALL(*gl_, PathCommandsNV(kServicePathId, kCorrectCommandCount, + commands, kCorrectCoordCount, GL_FLOAT, + coords)).RetiresOnSaturation(); + + cmds::PathCommandsCHROMIUM cmd; + + // Reference call -- this succeeds. + cmd.Init(client_path_id_, kCorrectCommandCount, shared_memory_id_, + shared_memory_offset_ + commands_offset, kCorrectCoordCount, + GL_FLOAT, shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + EXPECT_CALL(*gl_, PathCommandsNV(_, _, _, _, _, _)).Times(0); + + // Invalid client id fails. + cmd.Init(client_path_id_ - 1, kCorrectCommandCount, shared_memory_id_, + shared_memory_offset_, kCorrectCoordCount, GL_FLOAT, + shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + + // The numCommands < 0. + cmd.Init(client_path_id_, -1, shared_memory_id_, shared_memory_offset_, + kCorrectCoordCount, GL_FLOAT, shared_memory_id_, + shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); + + // The numCoords < 0. + cmd.Init(client_path_id_, kCorrectCommandCount, shared_memory_id_, + shared_memory_offset_, -1, GL_FLOAT, shared_memory_id_, + shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); + + // Invalid coordType fails. + cmd.Init(client_path_id_, kCorrectCommandCount, shared_memory_id_, + shared_memory_offset_, kCorrectCoordCount, kInvalidCoordType, + shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); + + // Big command counts. + cmd.Init(client_path_id_, std::numeric_limits<GLsizei>::max(), + shared_memory_id_, shared_memory_offset_ + commands_offset, + kCorrectCoordCount, GL_FLOAT, shared_memory_id_, + shared_memory_offset_); + EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + // Invalid SHM cases. + cmd.Init(client_path_id_, kCorrectCommandCount, kInvalidSharedMemoryId, + shared_memory_offset_ + commands_offset, kCorrectCoordCount, + GL_FLOAT, shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + cmd.Init(client_path_id_, kCorrectCommandCount, shared_memory_id_, + kInvalidSharedMemoryOffset, kCorrectCoordCount, GL_FLOAT, + shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + cmd.Init(client_path_id_, kCorrectCommandCount, shared_memory_id_, + shared_memory_offset_ + commands_offset, kCorrectCoordCount, + GL_FLOAT, kInvalidSharedMemoryId, shared_memory_offset_); + EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + cmd.Init(client_path_id_, kCorrectCommandCount, shared_memory_id_, + shared_memory_offset_ + commands_offset, kCorrectCoordCount, + GL_FLOAT, shared_memory_id_, kInvalidSharedMemoryOffset); + EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + // NULL shm command id with non-zero command count. + cmd.Init(client_path_id_, kCorrectCommandCount, 0, 0, kCorrectCoordCount, + GL_FLOAT, shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + // NULL shm coord id with non-zero coord count. + cmd.Init(client_path_id_, kCorrectCommandCount, shared_memory_id_, + shared_memory_offset_ + commands_offset, kCorrectCoordCount, + GL_FLOAT, 0, 0); + EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + // The coordCount not matching what is in commands. + // Expects kCorrectCoordCount+2 coords. + commands[1] = GL_MOVE_TO_CHROMIUM; + cmd.Init(client_path_id_, kCorrectCommandCount, shared_memory_id_, + shared_memory_offset_ + commands_offset, kCorrectCoordCount, + GL_FLOAT, shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + + // The coordCount not matching what is in commands. + // Expects kCorrectCoordCount-2 coords. + commands[0] = GL_CLOSE_PATH_CHROMIUM; + commands[1] = GL_CLOSE_PATH_CHROMIUM; + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + + // NULL shm coord ids. Currently causes gl error, though client should not let + // this through. + cmd.Init(client_path_id_, kCorrectCommandCount, shared_memory_id_, + shared_memory_offset_ + commands_offset, kCorrectCoordCount, + GL_FLOAT, 0, 0); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); +} + +TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, + PathCommandsCHROMIUMEmptyCommands) { + EXPECT_CALL(*gl_, PathCommandsNV(kServicePathId, 0, NULL, 0, GL_FLOAT, NULL)) + .RetiresOnSaturation(); + cmds::PathCommandsCHROMIUM cmd; + cmd.Init(client_path_id_, 0, 0, 0, 0, GL_FLOAT, 0, 0); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, + PathCommandsCHROMIUMInvalidCommands) { + EXPECT_CALL(*gl_, PathCommandsNV(_, _, _, _, _, _)).Times(0); + + cmds::PathCommandsCHROMIUM cmd; + + { + const GLsizei kCoordCount = 2; + const GLsizei kCommandCount = 2; + GLfloat* coords = GetSharedMemoryAs<GLfloat*>(); + unsigned commands_offset = sizeof(GLfloat) * kCoordCount; + GLubyte* commands = GetSharedMemoryAsWithOffset<GLubyte*>(commands_offset); + + coords[0] = 5.0f; + coords[1] = 5.0f; + commands[0] = 0x3; // Token MOVE_TO_RELATIVE in NV_path_rendering. + commands[1] = GL_CLOSE_PATH_CHROMIUM; + + cmd.Init(client_path_id_ - 1, kCommandCount, shared_memory_id_, + shared_memory_offset_, kCoordCount, GL_FLOAT, shared_memory_id_, + shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + } + { + const GLsizei kCoordCount = 8; + const GLsizei kCommandCount = 4; + GLfloat* coords = GetSharedMemoryAs<GLfloat*>(); + unsigned commands_offset = sizeof(GLfloat) * kCoordCount; + GLubyte* commands = GetSharedMemoryAsWithOffset<GLubyte*>(commands_offset); + + for (int i = 0; i < kCoordCount; ++i) { + coords[i] = 5.0f * i; + } + commands[0] = GL_MOVE_TO_CHROMIUM; + commands[1] = GL_MOVE_TO_CHROMIUM; + commands[2] = 'M'; // Synonym to MOVE_TO in NV_path_rendering. + commands[3] = GL_MOVE_TO_CHROMIUM; + + cmd.Init(client_path_id_ - 1, kCommandCount, shared_memory_id_, + shared_memory_offset_, kCoordCount, GL_FLOAT, shared_memory_id_, + shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + } +} + +TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, PathParameterXCHROMIUM) { + static GLuint kFirstClientID = client_path_id_ + 88; + static GLsizei kPathCount = 2; + static GLuint kFirstCreatedServiceID = 8000; + + // Create a paths so that we do not modify client_path_id_ + EXPECT_CALL(*gl_, GenPathsNV(kPathCount)) + .WillOnce(Return(kFirstCreatedServiceID)) + .RetiresOnSaturation(); + cmds::GenPathsCHROMIUM gen_cmd; + gen_cmd.Init(kFirstClientID, kPathCount); + EXPECT_EQ(error::kNoError, ExecuteCmd(gen_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + cmds::PathParameterfCHROMIUM fcmd; + cmds::PathParameteriCHROMIUM icmd; + const struct { + GLenum pname; + GLfloat value; + GLfloat expected_value; + } kTestcases[] = { + {GL_PATH_STROKE_WIDTH_CHROMIUM, 1.0f, 1.0f}, + {GL_PATH_STROKE_WIDTH_CHROMIUM, 0.0f, 0.0f}, + {GL_PATH_MITER_LIMIT_CHROMIUM, 500.0f, 500.0f}, + {GL_PATH_STROKE_BOUND_CHROMIUM, .80f, .80f}, + {GL_PATH_STROKE_BOUND_CHROMIUM, 1.80f, 1.0f}, + {GL_PATH_STROKE_BOUND_CHROMIUM, -1.0f, 0.0f}, + {GL_PATH_END_CAPS_CHROMIUM, GL_FLAT_CHROMIUM, GL_FLAT_CHROMIUM}, + {GL_PATH_END_CAPS_CHROMIUM, GL_SQUARE_CHROMIUM, GL_SQUARE_CHROMIUM}, + {GL_PATH_JOIN_STYLE_CHROMIUM, + GL_MITER_REVERT_CHROMIUM, + GL_MITER_REVERT_CHROMIUM}, + }; + + for (auto& testcase : kTestcases) { + EXPECT_CALL(*gl_, PathParameterfNV(kFirstCreatedServiceID, testcase.pname, + testcase.expected_value)) + .Times(1) + .RetiresOnSaturation(); + fcmd.Init(kFirstClientID, testcase.pname, testcase.value); + EXPECT_EQ(error::kNoError, ExecuteCmd(fcmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + EXPECT_CALL(*gl_, + PathParameteriNV(kFirstCreatedServiceID + 1, testcase.pname, + static_cast<GLint>(testcase.expected_value))) + .Times(1) + .RetiresOnSaturation(); + icmd.Init(kFirstClientID + 1, testcase.pname, + static_cast<GLint>(testcase.value)); + EXPECT_EQ(error::kNoError, ExecuteCmd(icmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + } + + // Cleanup. + EXPECT_CALL(*gl_, DeletePathsNV(kFirstCreatedServiceID, kPathCount)) + .RetiresOnSaturation(); + + cmds::DeletePathsCHROMIUM delete_cmd; + delete_cmd.Init(kFirstClientID, kPathCount); + EXPECT_EQ(error::kNoError, ExecuteCmd(delete_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, + PathParameterXCHROMIUMInvalidArgs) { + static GLuint kFirstClientID = client_path_id_ + 88; + static GLsizei kPathCount = 2; + static GLuint kFirstCreatedServiceID = 8000; + + // Create a paths so that we do not modify client_path_id_ + EXPECT_CALL(*gl_, GenPathsNV(kPathCount)) + .WillOnce(Return(kFirstCreatedServiceID)) + .RetiresOnSaturation(); + cmds::GenPathsCHROMIUM gen_cmd; + gen_cmd.Init(kFirstClientID, kPathCount); + EXPECT_EQ(error::kNoError, ExecuteCmd(gen_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + cmds::PathParameterfCHROMIUM fcmd; + cmds::PathParameteriCHROMIUM icmd; + const struct { + GLenum pname; + GLfloat value; + bool try_int_version; + GLint error; + } kTestcases[] = { + {GL_PATH_STROKE_WIDTH_CHROMIUM, -1.0f, true, GL_INVALID_VALUE}, + {GL_PATH_MITER_LIMIT_CHROMIUM, + std::numeric_limits<float>::infinity(), + false, + GL_INVALID_VALUE}, + {GL_PATH_MITER_LIMIT_CHROMIUM, + std::numeric_limits<float>::quiet_NaN(), + false, + GL_INVALID_VALUE}, + {GL_PATH_END_CAPS_CHROMIUM, 0x4, true, GL_INVALID_VALUE}, + {GL_PATH_END_CAPS_CHROMIUM, + GL_MITER_REVERT_CHROMIUM, + true, + GL_INVALID_VALUE}, + {GL_PATH_JOIN_STYLE_CHROMIUM, GL_FLAT_CHROMIUM, true, GL_INVALID_VALUE}, + {GL_PATH_MODELVIEW_CHROMIUM, GL_FLAT_CHROMIUM, true, GL_INVALID_ENUM}, + }; + + EXPECT_CALL(*gl_, PathParameterfNV(_, _, _)).Times(0); + EXPECT_CALL(*gl_, PathParameteriNV(_, _, _)).Times(0); + + for (auto& testcase : kTestcases) { + fcmd.Init(kFirstClientID, testcase.pname, testcase.value); + EXPECT_EQ(error::kNoError, ExecuteCmd(fcmd)); + EXPECT_EQ(testcase.error, GetGLError()); + if (!testcase.try_int_version) + continue; + + icmd.Init(kFirstClientID + 1, testcase.pname, + static_cast<GLint>(testcase.value)); + EXPECT_EQ(error::kNoError, ExecuteCmd(icmd)); + EXPECT_EQ(testcase.error, GetGLError()); + } + + // Cleanup. + EXPECT_CALL(*gl_, DeletePathsNV(kFirstCreatedServiceID, kPathCount)) + .RetiresOnSaturation(); + + cmds::DeletePathsCHROMIUM delete_cmd; + delete_cmd.Init(kFirstClientID, kPathCount); + EXPECT_EQ(error::kNoError, ExecuteCmd(delete_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, StencilFillPathCHROMIUM) { + SetupExpectationsForApplyingDefaultDirtyState(); + + cmds::StencilFillPathCHROMIUM cmd; + cmds::StencilThenCoverFillPathCHROMIUM tcmd; + + static const GLenum kFillModes[] = { + GL_INVERT, GL_COUNT_UP_CHROMIUM, GL_COUNT_DOWN_CHROMIUM}; + static const GLuint kMask = 0x7F; + + for (auto& fill_mode : kFillModes) { + EXPECT_CALL(*gl_, StencilFillPathNV(kServicePathId, fill_mode, kMask)) + .RetiresOnSaturation(); + cmd.Init(client_path_id_, fill_mode, kMask); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + EXPECT_CALL(*gl_, StencilThenCoverFillPathNV(kServicePathId, fill_mode, + kMask, GL_BOUNDING_BOX_NV)) + .RetiresOnSaturation(); + tcmd.Init(client_path_id_, fill_mode, kMask, GL_BOUNDING_BOX_CHROMIUM); + EXPECT_EQ(error::kNoError, ExecuteCmd(tcmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + } + + // Non-existent path: no error, no call. + cmd.Init(client_path_id_ - 1, GL_INVERT, 0x80); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + tcmd.Init(client_path_id_ - 1, GL_INVERT, 0x80, GL_BOUNDING_BOX_CHROMIUM); + EXPECT_EQ(error::kNoError, ExecuteCmd(tcmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, + StencilFillPathCHROMIUMInvalidArgs) { + EXPECT_CALL(*gl_, StencilFillPathNV(_, _, _)).Times(0); + EXPECT_CALL(*gl_, StencilThenCoverFillPathNV(_, _, _, GL_BOUNDING_BOX_NV)) + .Times(0); + + cmds::StencilFillPathCHROMIUM cmd; + cmds::StencilThenCoverFillPathCHROMIUM tcmd; + + cmd.Init(client_path_id_, GL_INVERT - 1, 0x80); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); + + tcmd.Init(client_path_id_, GL_INVERT - 1, 0x80, GL_BOUNDING_BOX_CHROMIUM); + EXPECT_EQ(error::kNoError, ExecuteCmd(tcmd)); + EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); + + // The /mask/+1 is not power of two -> invalid value. + cmd.Init(client_path_id_, GL_COUNT_UP_CHROMIUM, 0x80); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); + + tcmd.Init(client_path_id_, GL_COUNT_UP_CHROMIUM, 0x80, + GL_BOUNDING_BOX_CHROMIUM); + EXPECT_EQ(error::kNoError, ExecuteCmd(tcmd)); + EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); + + cmd.Init(client_path_id_, GL_COUNT_DOWN_CHROMIUM, 5); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); + + tcmd.Init(client_path_id_, GL_COUNT_DOWN_CHROMIUM, 5, + GL_BOUNDING_BOX_CHROMIUM); + EXPECT_EQ(error::kNoError, ExecuteCmd(tcmd)); + EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); +} + +TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, StencilStrokePathCHROMIUM) { + SetupExpectationsForApplyingDefaultDirtyState(); + + EXPECT_CALL(*gl_, StencilStrokePathNV(kServicePathId, 1, 0x80)) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, StencilThenCoverStrokePathNV(kServicePathId, 1, 0x80, + GL_BOUNDING_BOX_NV)) + .RetiresOnSaturation(); + + cmds::StencilStrokePathCHROMIUM cmd; + cmds::StencilThenCoverStrokePathCHROMIUM tcmd; + + cmd.Init(client_path_id_, 1, 0x80); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + tcmd.Init(client_path_id_, 1, 0x80, GL_BOUNDING_BOX_CHROMIUM); + EXPECT_EQ(error::kNoError, ExecuteCmd(tcmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + EXPECT_CALL(*gl_, StencilThenCoverStrokePathNV(kServicePathId, 1, 0x80, + GL_CONVEX_HULL_NV)) + .RetiresOnSaturation(); + + tcmd.Init(client_path_id_, 1, 0x80, GL_CONVEX_HULL_CHROMIUM); + EXPECT_EQ(error::kNoError, ExecuteCmd(tcmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + // Non-existent path: no error, no call. + cmd.Init(client_path_id_ - 1, 1, 0x80); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + tcmd.Init(client_path_id_ - 1, 1, 0x80, GL_BOUNDING_BOX_CHROMIUM); + EXPECT_EQ(error::kNoError, ExecuteCmd(tcmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, CoverFillPathCHROMIUM) { + SetupExpectationsForApplyingDefaultDirtyState(); + + EXPECT_CALL(*gl_, CoverFillPathNV(kServicePathId, GL_BOUNDING_BOX_NV)) + .RetiresOnSaturation(); + cmds::CoverFillPathCHROMIUM cmd; + cmd.Init(client_path_id_, GL_BOUNDING_BOX_CHROMIUM); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + EXPECT_CALL(*gl_, CoverFillPathNV(kServicePathId, GL_CONVEX_HULL_NV)) + .RetiresOnSaturation(); + cmd.Init(client_path_id_, GL_CONVEX_HULL_CHROMIUM); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + // Non-existent path: no error, no call. + cmd.Init(client_path_id_ - 1, GL_BOUNDING_BOX_CHROMIUM); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, CoverStrokePathCHROMIUM) { + SetupExpectationsForApplyingDefaultDirtyState(); + EXPECT_CALL(*gl_, CoverStrokePathNV(kServicePathId, GL_BOUNDING_BOX_NV)) + .RetiresOnSaturation(); + cmds::CoverStrokePathCHROMIUM cmd; + cmd.Init(client_path_id_, GL_BOUNDING_BOX_CHROMIUM); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + EXPECT_CALL(*gl_, CoverStrokePathNV(kServicePathId, GL_CONVEX_HULL_NV)) + .RetiresOnSaturation(); + cmd.Init(client_path_id_, GL_CONVEX_HULL_CHROMIUM); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + // Non-existent path: no error, no call. + cmd.Init(client_path_id_ - 1, GL_BOUNDING_BOX_CHROMIUM); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +namespace { +template <typename T> +struct gl_type_enum {}; +template <> +struct gl_type_enum<GLbyte> { + enum { kGLType = GL_BYTE }; +}; +template <> +struct gl_type_enum<GLubyte> { + enum { kGLType = GL_UNSIGNED_BYTE }; +}; +template <> +struct gl_type_enum<GLshort> { + enum { kGLType = GL_SHORT }; +}; +template <> +struct gl_type_enum<GLushort> { + enum { kGLType = GL_UNSIGNED_SHORT }; +}; +template <> +struct gl_type_enum<GLfloat> { + enum { kGLType = GL_FLOAT }; +}; +} + +template <typename TypeParam> +void GLES2DecoderTestWithCHROMIUMPathRendering:: + TestPathCommandsCHROMIUMCoordTypes() { + static const GLsizei kCorrectCoordCount = 19; + static const GLsizei kCorrectCommandCount = 6; + + TypeParam* coords = GetSharedMemoryAs<TypeParam*>(); + unsigned commands_offset = sizeof(TypeParam) * kCorrectCoordCount; + GLubyte* commands = GetSharedMemoryAsWithOffset<GLubyte*>(commands_offset); + for (int i = 0; i < kCorrectCoordCount; ++i) { + coords[i] = static_cast<TypeParam>(5 * i); + } + commands[0] = GL_MOVE_TO_CHROMIUM; + commands[1] = GL_CLOSE_PATH_CHROMIUM; + commands[2] = GL_LINE_TO_CHROMIUM; + commands[3] = GL_QUADRATIC_CURVE_TO_CHROMIUM; + commands[4] = GL_CUBIC_CURVE_TO_CHROMIUM; + commands[5] = GL_CONIC_CURVE_TO_CHROMIUM; + + EXPECT_CALL(*gl_, PathCommandsNV(kServicePathId, kCorrectCommandCount, + commands, kCorrectCoordCount, + gl_type_enum<TypeParam>::kGLType, coords)) + .RetiresOnSaturation(); + + cmds::PathCommandsCHROMIUM cmd; + + cmd.Init(client_path_id_, kCorrectCommandCount, shared_memory_id_, + shared_memory_offset_ + commands_offset, kCorrectCoordCount, + gl_type_enum<TypeParam>::kGLType, shared_memory_id_, + shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, + PathCommandsCHROMIUMCoordTypes) { + // Not using a typed test case, because the base class is already parametrized + // test case and uses GetParam. + TestPathCommandsCHROMIUMCoordTypes<GLbyte>(); + TestPathCommandsCHROMIUMCoordTypes<GLubyte>(); + TestPathCommandsCHROMIUMCoordTypes<GLshort>(); + TestPathCommandsCHROMIUMCoordTypes<GLushort>(); + TestPathCommandsCHROMIUMCoordTypes<GLfloat>(); +} + #include "gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions_autogen.h" } // namespace gles2 diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions_autogen.h index 57db672..5c22b6c 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions_autogen.h @@ -44,6 +44,55 @@ TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); EXPECT_EQ(GL_NO_ERROR, GetGLError()); } +// TODO(gman): GenPathsCHROMIUM + +// TODO(gman): DeletePathsCHROMIUM + +TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, IsPathCHROMIUMValidArgs) { + EXPECT_CALL(*gl_, IsPathNV(kServicePathId)); + SpecializedSetup<cmds::IsPathCHROMIUM, 0>(true); + cmds::IsPathCHROMIUM cmd; + cmd.Init(client_path_id_, shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, + IsPathCHROMIUMInvalidArgsBadSharedMemoryId) { + EXPECT_CALL(*gl_, IsPathNV(kServicePathId)).Times(0); + SpecializedSetup<cmds::IsPathCHROMIUM, 0>(false); + cmds::IsPathCHROMIUM cmd; + cmd.Init(client_path_id_, kInvalidSharedMemoryId, shared_memory_offset_); + EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); + cmd.Init(client_path_id_, shared_memory_id_, kInvalidSharedMemoryOffset); + EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); +} +// TODO(gman): PathCommandsCHROMIUM + +// TODO(gman): PathParameterfCHROMIUM + +// TODO(gman): PathParameteriCHROMIUM + +TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, + PathStencilFuncCHROMIUMValidArgs) { + EXPECT_CALL(*gl_, PathStencilFuncNV(GL_NEVER, 2, 3)); + SpecializedSetup<cmds::PathStencilFuncCHROMIUM, 0>(true); + cmds::PathStencilFuncCHROMIUM cmd; + cmd.Init(GL_NEVER, 2, 3); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} +// TODO(gman): StencilFillPathCHROMIUM + +// TODO(gman): StencilStrokePathCHROMIUM + +// TODO(gman): CoverFillPathCHROMIUM + +// TODO(gman): CoverStrokePathCHROMIUM + +// TODO(gman): StencilThenCoverFillPathCHROMIUM + +// TODO(gman): StencilThenCoverStrokePathCHROMIUM TEST_P(GLES2DecoderTestWithBlendEquationAdvanced, BlendBarrierKHRValidArgs) { EXPECT_CALL(*gl_, BlendBarrierKHR()); diff --git a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h index ec96c6b..ccaeb59 100644 --- a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h @@ -46,6 +46,12 @@ ValueValidator<GLenum> internal_format_parameter; ValueValidator<GLenum> invalidate_frame_buffer_target; ValueValidator<GLenum> map_buffer_access; ValueValidator<GLenum> matrix_mode; +ValueValidator<GLenum> path_coord_type; +ValueValidator<GLenum> path_cover_mode; +ValueValidator<GLenum> path_fill_mode; +ValueValidator<GLenum> path_parameter; +ValueValidator<GLint> path_parameter_cap_values; +ValueValidator<GLint> path_parameter_join_values; ValueValidator<GLenum> pixel_store; ValueValidator<GLint> pixel_store_alignment; ValueValidator<GLenum> pixel_type; diff --git a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h index 1c4cf97..5e23712 100644 --- a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h @@ -474,6 +474,45 @@ static const GLenum valid_matrix_mode_table[] = { GL_PATH_MODELVIEW_CHROMIUM, }; +static const GLenum valid_path_coord_type_table[] = { + GL_BYTE, + GL_UNSIGNED_BYTE, + GL_SHORT, + GL_UNSIGNED_SHORT, + GL_FLOAT, +}; + +static const GLenum valid_path_cover_mode_table[] = { + GL_CONVEX_HULL_CHROMIUM, + GL_BOUNDING_BOX_CHROMIUM, +}; + +static const GLenum valid_path_fill_mode_table[] = { + GL_INVERT, + GL_COUNT_UP_CHROMIUM, + GL_COUNT_DOWN_CHROMIUM, +}; + +static const GLenum valid_path_parameter_table[] = { + GL_PATH_STROKE_WIDTH_CHROMIUM, + GL_PATH_END_CAPS_CHROMIUM, + GL_PATH_JOIN_STYLE_CHROMIUM, + GL_PATH_MITER_LIMIT_CHROMIUM, + GL_PATH_STROKE_BOUND_CHROMIUM, +}; + +static const GLint valid_path_parameter_cap_values_table[] = { + GL_FLAT, + GL_SQUARE_CHROMIUM, + GL_ROUND_CHROMIUM, +}; + +static const GLint valid_path_parameter_join_values_table[] = { + GL_MITER_REVERT_CHROMIUM, + GL_BEVEL_CHROMIUM, + GL_ROUND_CHROMIUM, +}; + static const GLenum valid_pixel_store_table[] = { GL_PACK_ALIGNMENT, GL_UNPACK_ALIGNMENT, @@ -1148,6 +1187,20 @@ Validators::Validators() map_buffer_access(valid_map_buffer_access_table, arraysize(valid_map_buffer_access_table)), matrix_mode(valid_matrix_mode_table, arraysize(valid_matrix_mode_table)), + path_coord_type(valid_path_coord_type_table, + arraysize(valid_path_coord_type_table)), + path_cover_mode(valid_path_cover_mode_table, + arraysize(valid_path_cover_mode_table)), + path_fill_mode(valid_path_fill_mode_table, + arraysize(valid_path_fill_mode_table)), + path_parameter(valid_path_parameter_table, + arraysize(valid_path_parameter_table)), + path_parameter_cap_values( + valid_path_parameter_cap_values_table, + arraysize(valid_path_parameter_cap_values_table)), + path_parameter_join_values( + valid_path_parameter_join_values_table, + arraysize(valid_path_parameter_join_values_table)), pixel_store(valid_pixel_store_table, arraysize(valid_pixel_store_table)), pixel_store_alignment(valid_pixel_store_alignment_table, arraysize(valid_pixel_store_alignment_table)), diff --git a/gpu/command_buffer/service/gpu_switches.cc b/gpu/command_buffer/service/gpu_switches.cc index d2ca490..171f543 100644 --- a/gpu/command_buffer/service/gpu_switches.cc +++ b/gpu/command_buffer/service/gpu_switches.cc @@ -71,25 +71,31 @@ const char kGLShaderIntermOutput[] = "gl-shader-interm-output"; // round intermediate values in ANGLE. const char kEmulateShaderPrecision[] = "emulate-shader-precision"; +// Enables using path rendering implementation implemented currently +// in NV_path_rendering OpenGL extension. Requires compatible hardware +// and driver. This is used in GPU rasterization. +const char kEnableGLPathRendering[] = "enable-gl-path-rendering"; + const char* kGpuSwitches[] = { - kCompileShaderAlwaysSucceeds, - kDisableGLErrorLimit, - kDisableGLSLTranslator, - kDisableGpuDriverBugWorkarounds, - kDisableShaderNameHashing, - kEnableGPUCommandLogging, - kEnableGPUDebugging, - kEnableGPUServiceLoggingGPU, - kDisableGpuProgramCache, - kEnforceGLMinimums, - kForceGpuMemAvailableMb, - kGpuDriverBugWorkarounds, - kGpuProgramCacheSizeKb, - kDisableGpuShaderDiskCache, - kEnableShareGroupAsyncTextureUpload, - kEnableSubscribeUniformExtension, - kGLShaderIntermOutput, - kEmulateShaderPrecision, + kCompileShaderAlwaysSucceeds, + kDisableGLErrorLimit, + kDisableGLSLTranslator, + kDisableGpuDriverBugWorkarounds, + kDisableShaderNameHashing, + kEnableGPUCommandLogging, + kEnableGPUDebugging, + kEnableGPUServiceLoggingGPU, + kDisableGpuProgramCache, + kEnforceGLMinimums, + kForceGpuMemAvailableMb, + kGpuDriverBugWorkarounds, + kGpuProgramCacheSizeKb, + kDisableGpuShaderDiskCache, + kEnableShareGroupAsyncTextureUpload, + kEnableSubscribeUniformExtension, + kGLShaderIntermOutput, + kEmulateShaderPrecision, + kEnableGLPathRendering, }; const int kNumGpuSwitches = arraysize(kGpuSwitches); diff --git a/gpu/command_buffer/service/gpu_switches.h b/gpu/command_buffer/service/gpu_switches.h index ac6883a..ac347e4 100644 --- a/gpu/command_buffer/service/gpu_switches.h +++ b/gpu/command_buffer/service/gpu_switches.h @@ -30,6 +30,7 @@ GPU_EXPORT extern const char kEnableSubscribeUniformExtension[]; GPU_EXPORT extern const char kEnableThreadedTextureMailboxes[]; GPU_EXPORT extern const char kGLShaderIntermOutput[]; GPU_EXPORT extern const char kEmulateShaderPrecision[]; +GPU_EXPORT extern const char kEnableGLPathRendering[]; GPU_EXPORT extern const char* kGpuSwitches[]; GPU_EXPORT extern const int kNumGpuSwitches; diff --git a/gpu/command_buffer/service/path_manager.cc b/gpu/command_buffer/service/path_manager.cc new file mode 100644 index 0000000..3e0d257 --- /dev/null +++ b/gpu/command_buffer/service/path_manager.cc @@ -0,0 +1,252 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gpu/command_buffer/service/path_manager.h" + +#include <algorithm> + +#include "base/logging.h" +#include "gpu/command_buffer/common/gles2_cmd_utils.h" +#include "ui/gl/gl_bindings.h" + +namespace gpu { +namespace gles2 { + +namespace { +void CallDeletePaths(GLuint first_id, GLuint range) { + while (range > 0) { + GLsizei irange; + if (range > static_cast<GLuint>(std::numeric_limits<GLsizei>::max())) + irange = std::numeric_limits<GLsizei>::max(); + else + irange = static_cast<GLsizei>(range); + + glDeletePathsNV(first_id, irange); + range -= irange; + first_id += irange; + } +} + +template <typename RangeIterator> +static GLuint RangeSize(const RangeIterator& it) { + return it->second.last_client_id - it->first + 1; +} +template <typename RangeIterator> +static GLuint FirstClientId(const RangeIterator& it) { + return it->first; +} +template <typename RangeIterator> +static GLuint FirstServiceId(const RangeIterator& it) { + return it->second.first_service_id; +} +template <typename RangeIterator> +static GLuint LastServiceId(const RangeIterator& it) { + return FirstServiceId(it) + RangeSize(it) - 1; +} +static GLuint LastClientId(PathManager::PathRangeMap::const_iterator& it) { + return it->second.last_client_id; +} +// Note: this one can be assigned to. +static GLuint& LastClientId(PathManager::PathRangeMap::iterator& it) { + return it->second.last_client_id; +} + +template <typename T> +struct IteratorSelector { + typedef typename T::iterator iterator; +}; +template <typename T> +struct IteratorSelector<const T> { + typedef typename T::const_iterator iterator; +}; + +// Returns the range position that contains |client_id| or +// |PathRangeMap::iterator::end()| if |client_id| is not found. +template <typename MapType> +static typename IteratorSelector<MapType>::iterator GetContainingRange( + MapType& path_map, + GLuint client_id) { + auto it = path_map.lower_bound(client_id); + if (it != path_map.end() && FirstClientId(it) == client_id) + return it; + if (it != path_map.begin()) { + --it; + if (LastClientId(it) >= client_id) + return it; + } + return path_map.end(); +} + +// Returns the range position that contains |client_id|. If that is +// not available, returns the range that has smallest +// |first_client_id| that is bigger than |client_id|. Returns +// |PathRangeMap::iterator::end()| if there is no such range. +template <typename MapType> +static typename IteratorSelector<MapType>::iterator GetContainingOrNextRange( + MapType& path_map, + GLuint client_id) { + auto it = path_map.lower_bound(client_id); + if (it != path_map.end() && FirstClientId(it) == client_id) { + return it; + } + if (it != path_map.begin()) { + --it; + if (LastClientId(it) >= client_id) + return it; + ++it; + } + return it; +} + +} // anonymous namespace + +PathManager::PathManager() { +} + +PathManager::~PathManager() { + DCHECK(path_map_.empty()); +} + +void PathManager::Destroy(bool have_context) { + if (have_context) { + for (PathRangeMap::const_iterator it = path_map_.begin(); + it != path_map_.end(); ++it) + CallDeletePaths(FirstServiceId(it), RangeSize(it)); + } + path_map_.clear(); +} + +void PathManager::CreatePathRange(GLuint first_client_id, + GLuint last_client_id, + GLuint first_service_id) { + DCHECK(first_service_id > 0u); + DCHECK(first_client_id > 0u); + DCHECK(!HasPathsInRange(first_client_id, last_client_id)); + DCHECK(CheckConsistency()); + + PathRangeMap::iterator range = + GetContainingRange(path_map_, first_client_id - 1u); + + if (range != path_map_.end() && + LastServiceId(range) == first_service_id - 1u) { + DCHECK_EQ(LastClientId(range), first_client_id - 1u); + LastClientId(range) = last_client_id; + } else { + auto result = path_map_.insert( + std::make_pair(first_client_id, + PathRangeDescription(last_client_id, first_service_id))); + DCHECK(result.second); + range = result.first; + } + + PathRangeMap::iterator next_range = range; + ++next_range; + if (next_range != path_map_.end()) { + if (LastClientId(range) == FirstClientId(next_range) - 1u && + LastServiceId(range) == FirstServiceId(next_range) - 1u) { + LastClientId(range) = LastClientId(next_range); + path_map_.erase(next_range); + } + } + DCHECK(CheckConsistency()); +} + +bool PathManager::HasPathsInRange(GLuint first_client_id, + GLuint last_client_id) const { + PathRangeMap::const_iterator it = + GetContainingOrNextRange(path_map_, first_client_id); + if (it == path_map_.end()) + return false; + + return FirstClientId(it) <= last_client_id; +} + +bool PathManager::GetPath(GLuint client_id, GLuint* service_id) const { + PathRangeMap::const_iterator range = GetContainingRange(path_map_, client_id); + if (range == path_map_.end()) + return false; + + *service_id = FirstServiceId(range) + client_id - FirstClientId(range); + return true; +} + +void PathManager::RemovePaths(GLuint first_client_id, GLuint last_client_id) { + DCHECK(CheckConsistency()); + PathRangeMap::iterator it = + GetContainingOrNextRange(path_map_, first_client_id); + + while (it != path_map_.end() && FirstClientId(it) <= last_client_id) { + GLuint delete_first_client_id = + std::max(first_client_id, FirstClientId(it)); + GLuint delete_last_client_id = std::min(last_client_id, LastClientId(it)); + GLuint delete_first_service_id = + FirstServiceId(it) + delete_first_client_id - FirstClientId(it); + GLuint delete_range = delete_last_client_id - delete_first_client_id + 1u; + + CallDeletePaths(delete_first_service_id, delete_range); + + PathRangeMap::iterator current = it; + ++it; + + GLuint current_last_client_id = LastClientId(current); + + if (FirstClientId(current) < delete_first_client_id) + LastClientId(current) = delete_first_client_id - 1u; + else + path_map_.erase(current); + + if (current_last_client_id > delete_last_client_id) { + path_map_.insert(std::make_pair( + delete_last_client_id + 1u, + PathRangeDescription(current_last_client_id, + delete_first_service_id + delete_range))); + DCHECK(delete_last_client_id == last_client_id); + // This is necessarily the last range to check. Return early due to + // consistency. Iterator increment would skip the inserted range. The + // algorithm would work ok, but it looks weird. + DCHECK(CheckConsistency()); + return; + } + } + DCHECK(CheckConsistency()); +} + +bool PathManager::CheckConsistency() { + GLuint prev_first_client_id = 0u; + GLuint prev_last_client_id = 0u; + GLuint prev_first_service_id = 0u; + for (PathRangeMap::iterator range = path_map_.begin(); + range != path_map_.end(); ++range) { + // Code relies on ranges not starting at 0. Also, the above initialization + // is only + // correct then. + if (FirstClientId(range) == 0u || FirstServiceId(range) == 0u) + return false; + + // Each range is consistent. + if (FirstClientId(range) > LastClientId(range)) + return false; + + if (prev_first_client_id != 0u) { + // No overlapping ranges. (The iteration is sorted). + if (FirstClientId(range) <= prev_last_client_id) + return false; + + // No mergeable ranges. + bool is_mergeable_client = + FirstClientId(range) - 1u == prev_last_client_id; + bool is_mergeable_service = + FirstServiceId(range) - 1u == prev_first_service_id; + if (is_mergeable_client && is_mergeable_service) + return false; + } + prev_first_client_id = FirstClientId(range); + prev_last_client_id = LastClientId(range); + prev_first_service_id = FirstServiceId(range); + } + return true; +} + +} // namespace gles2 +} // namespace gpu diff --git a/gpu/command_buffer/service/path_manager.h b/gpu/command_buffer/service/path_manager.h new file mode 100644 index 0000000..78a53b7 --- /dev/null +++ b/gpu/command_buffer/service/path_manager.h @@ -0,0 +1,68 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_PATH_MANAGER_H_ +#define GPU_COMMAND_BUFFER_SERVICE_PATH_MANAGER_H_ + +#include <map> + +#include "base/basictypes.h" +#include "gpu/command_buffer/service/gl_utils.h" +#include "gpu/gpu_export.h" + +namespace gpu { +namespace gles2 { + +// This class keeps track of paths and their client and service ids +// so we can correctly clear them. +class GPU_EXPORT PathManager { + public: + PathManager(); + ~PathManager(); + + // Must call before destruction. + void Destroy(bool have_context); + + // Creates a path mapping between closed intervals + // [first_client_id, last_client_id] -> [first_service_id, ...]. + void CreatePathRange(GLuint first_client_id, + GLuint last_client_id, + GLuint first_service_id); + + // Returns true if any path exists in the closed interval + // [first_client_id, last_client_id]. + bool HasPathsInRange(GLuint first_client_id, GLuint last_client_id) const; + + // Gets the path id corresponding the client path id. + // Returns false if no such service path id was not found. + bool GetPath(GLuint client_id, GLuint* service_id) const; + + // Removes a closed interval of paths [first_client_id, last_client_id]. + void RemovePaths(GLuint first_client_id, GLuint last_client_id); + + // Mapping between client id and service id. + // Should be used only by the implementation. + struct PathRangeDescription { + PathRangeDescription(GLuint last_client, GLuint first_service) + : last_client_id(last_client), first_service_id(first_service) {} + GLuint last_client_id; + GLuint first_service_id; + typedef GLuint ServiceIdType; + }; + typedef std::map<GLuint, PathRangeDescription> PathRangeMap; + + private: + // Checks for consistency inside the book-keeping structures. Used as + // DCHECK pre/post condition in mutating functions. + bool CheckConsistency(); + + PathRangeMap path_map_; + + DISALLOW_COPY_AND_ASSIGN(PathManager); +}; + +} // namespace gles2 +} // namespace gpu + +#endif // GPU_COMMAND_BUFFER_SERVICE_PATH_MANAGER_H_ diff --git a/gpu/command_buffer/service/path_manager_unittest.cc b/gpu/command_buffer/service/path_manager_unittest.cc new file mode 100644 index 0000000..8a20db5 --- /dev/null +++ b/gpu/command_buffer/service/path_manager_unittest.cc @@ -0,0 +1,164 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gpu/command_buffer/service/path_manager.h" + +#include "base/memory/scoped_ptr.h" +#include "gpu/command_buffer/service/gpu_service_test.h" +#include "gpu/command_buffer/service/mocks.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gl/gl_mock.h" + +namespace gpu { +namespace gles2 { + +class PathManagerTest : public GpuServiceTest { + public: + PathManagerTest() {} + + protected: + void SetUp() override { + SetUpWithGLVersion("3.0", "GL_NV_path_rendering"); + manager_.reset(new PathManager()); + } + + void TearDown() override { + manager_->Destroy(true); + manager_.reset(); + GpuServiceTest::TearDown(); + } + + scoped_ptr<PathManager> manager_; +}; + +TEST_F(PathManagerTest, Basic) { + const GLuint kClient1Id = 1; + const GLuint kService1Id = 11; + const GLuint kClient2Id = 2; + GLuint service_id = 0; + manager_->CreatePathRange(kClient1Id, kClient1Id, kService1Id); + ASSERT_TRUE(manager_->HasPathsInRange(kClient1Id, kClient1Id)); + EXPECT_TRUE(manager_->GetPath(kClient1Id, &service_id)); + EXPECT_EQ(kService1Id, service_id); + + // Check we get nothing for a non-existent path. + service_id = 123u; + ASSERT_FALSE(manager_->HasPathsInRange(kClient2Id, kClient2Id)); + EXPECT_FALSE(manager_->GetPath(kClient2Id, &service_id)); + EXPECT_EQ(123u, service_id); + + // Check trying to remove non-existent paths does not crash. + manager_->RemovePaths(kClient2Id, kClient2Id); + + // Check that it gets deleted when the last reference is released. + EXPECT_CALL(*gl_, DeletePathsNV(kService1Id, 1)) + .Times(1) + .RetiresOnSaturation(); + + // Check we can't get the path after we remove it. + manager_->RemovePaths(kClient1Id, kClient1Id); + ASSERT_FALSE(manager_->HasPathsInRange(kClient1Id, kClient1Id)); + EXPECT_FALSE(manager_->GetPath(kClient1Id, &service_id)); +} + +// Tests that path manager does not merge ranges that contain service ids that +// prevent the merging. Path ranges A and B can be merged if +// * client ids of B start immediately after the last client id of A +// * service ids of B start immediately after the last service id of A +// and similarly for the 'before' case. +TEST_F(PathManagerTest, NonContiguousServiceIds) { + const GLuint kMergeCheckRange = 54; + + const struct { + GLuint first_client_id; + GLuint last_client_id; + GLuint first_service_id; + } kIdRanges[] = {{500, 1000, 900}, {1001, 1155, 1}, {200, 499, 4888}}; + for (auto& range : kIdRanges) { + manager_->CreatePathRange(range.first_client_id, range.last_client_id, + range.first_service_id); + ASSERT_TRUE(manager_->HasPathsInRange(range.first_client_id, + range.first_client_id)); + ASSERT_TRUE( + manager_->HasPathsInRange(range.last_client_id, range.last_client_id)); + ASSERT_TRUE( + manager_->HasPathsInRange(range.first_client_id, range.last_client_id)); + GLuint service_id = 0u; + EXPECT_TRUE(manager_->GetPath(range.first_client_id + 5u, &service_id)); + EXPECT_EQ(range.first_service_id + 5u, service_id); + } + + // Insert a mergeable range last, to check that merges + // work. Otherwise the test could succeed because merges were not + // working. + auto& merge_candidate = kIdRanges[1]; + GLuint merge_candidate_range = + merge_candidate.last_client_id - merge_candidate.first_client_id + 1; + manager_->CreatePathRange( + merge_candidate.last_client_id + 1, + merge_candidate.last_client_id + kMergeCheckRange, + merge_candidate.first_service_id + merge_candidate_range); + + // We detect that ranges were not merged accidentally by detecting individual + // deletes. + for (auto& range : kIdRanges) { + if (&range == &merge_candidate) + continue; + GLsizei range_amount = range.last_client_id - range.first_client_id + 1; + EXPECT_CALL(*gl_, DeletePathsNV(range.first_service_id, range_amount)) + .Times(1) + .RetiresOnSaturation(); + } + + // Just a check that merges work. + EXPECT_CALL(*gl_, DeletePathsNV(merge_candidate.first_service_id, + merge_candidate_range + kMergeCheckRange)) + .Times(1) + .RetiresOnSaturation(); + + // Remove all ids. This should cause the expected amount of DeletePathsNV + // calls. + manager_->RemovePaths(1, std::numeric_limits<GLsizei>::max()); + + for (auto& range : kIdRanges) { + ASSERT_FALSE( + manager_->HasPathsInRange(range.first_client_id, range.last_client_id)); + } +} + +TEST_F(PathManagerTest, DeleteBigRange) { + // Allocates two ranges which in path manager end up merging as one + // big range. The range will be too big to fit in one DeletePaths + // call. Test that the range is deleted correctly with two calls. + const GLuint kFirstClientId1 = 1; + const GLsizei kRange1 = std::numeric_limits<GLsizei>::max() - 3; + const GLuint kLastClientId1 = kFirstClientId1 + kRange1 - 1; + const GLuint kFirstServiceId1 = 77; + const GLuint kLastServiceId1 = kFirstServiceId1 + kRange1 - 1; + + const GLuint kFirstClientId2 = kLastClientId1 + 1; + const GLsizei kRange2 = 15; + const GLuint kLastClientId2 = kFirstClientId2 + kRange2 - 1; + const GLuint kFirstServiceId2 = kLastServiceId1 + 1; + + const GLsizei kFirstDeleteRange = std::numeric_limits<GLsizei>::max(); + const GLsizei kSecondDeleteRange = kRange2 - (kFirstDeleteRange - kRange1); + const GLuint kSecondDeleteFirstServiceId = + kFirstServiceId1 + kFirstDeleteRange; + + EXPECT_CALL(*gl_, DeletePathsNV(kFirstServiceId1, + std::numeric_limits<GLsizei>::max())) + .RetiresOnSaturation(); + + EXPECT_CALL(*gl_, DeletePathsNV(kSecondDeleteFirstServiceId, + kSecondDeleteRange)).RetiresOnSaturation(); + + manager_->CreatePathRange(kFirstClientId1, kLastClientId1, kFirstServiceId1); + manager_->CreatePathRange(kFirstClientId2, kLastClientId2, kFirstServiceId2); + manager_->RemovePaths(0, std::numeric_limits<GLuint>::max()); +} + +} // namespace gles2 + +} // namespace gpu diff --git a/gpu/command_buffer/tests/gl_chromium_path_rendering_unittest.cc b/gpu/command_buffer/tests/gl_chromium_path_rendering_unittest.cc index 0d17b7c..57f5dd0 100644 --- a/gpu/command_buffer/tests/gl_chromium_path_rendering_unittest.cc +++ b/gpu/command_buffer/tests/gl_chromium_path_rendering_unittest.cc @@ -7,11 +7,15 @@ #include <GLES2/gl2extchromium.h> #include <cmath> +#include "base/command_line.h" +#include "gpu/command_buffer/service/gpu_switches.h" #include "gpu/command_buffer/tests/gl_manager.h" #include "gpu/command_buffer/tests/gl_test_utils.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#define SHADER(Src) #Src + namespace gpu { class CHROMIUMPathRenderingTest : public testing::Test { @@ -22,7 +26,9 @@ class CHROMIUMPathRenderingTest : public testing::Test { void SetUp() override { GLManager::Options options; options.size = gfx::Size(kResolution, kResolution); - gl_.Initialize(options); + base::CommandLine command_line(*base::CommandLine::ForCurrentProcess()); + command_line.AppendSwitch(switches::kEnableGLPathRendering); + gl_.InitializeWithCommandLine(options, &command_line); } void TearDown() override { gl_.Destroy(); } @@ -37,13 +43,156 @@ class CHROMIUMPathRenderingTest : public testing::Test { EXPECT_EQ(static_cast<GLint>(round(expected[i])), actual[i]); } } + + void SetupStateForTestPattern() { + glViewport(0, 0, kResolution, kResolution); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glStencilMask(0xffffffff); + glClearStencil(0); + glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + + static const char* kVertexShaderSource = + SHADER(void main() { gl_Position = vec4(1); }); + static const char* kFragmentShaderSource = + SHADER(precision mediump float; uniform vec4 color; + void main() { gl_FragColor = color; }); + + GLuint program = + GLTestHelper::LoadProgram(kVertexShaderSource, kFragmentShaderSource); + glUseProgram(program); + color_loc_ = glGetUniformLocation(program, "color"); + glDeleteProgram(program); + + // Set up orthogonal projection with near/far plane distance of 2. + static GLfloat matrix[16] = {2.0f / (kResolution - 1), + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 2.0f / (kResolution - 1), + 0.0f, + 0.0f, + 0.0f, + 0.0f, + -1.0f, + 0.0f, + -1.0f, + -1.0f, + 0.0f, + 1.0f}; + glMatrixLoadfCHROMIUM(GL_PATH_PROJECTION_CHROMIUM, matrix); + glMatrixLoadIdentityCHROMIUM(GL_PATH_MODELVIEW_CHROMIUM); + + glEnable(GL_STENCIL_TEST); + + GLTestHelper::CheckGLError("no errors at state setup", __LINE__); + } + + void SetupPathStateForTestPattern(GLuint path) { + static const GLubyte kCommands[] = {GL_MOVE_TO_CHROMIUM, + GL_LINE_TO_CHROMIUM, + GL_QUADRATIC_CURVE_TO_CHROMIUM, + GL_CUBIC_CURVE_TO_CHROMIUM, + GL_CLOSE_PATH_CHROMIUM}; + + static const GLfloat kCoords[] = {50.0f, + 50.0f, + 75.0f, + 75.0f, + 100.0f, + 62.5f, + 50.0f, + 25.5f, + 0.0f, + 62.5f, + 50.0f, + 50.0f, + 25.0f, + 75.0f}; + + glPathCommandsCHROMIUM(path, arraysize(kCommands), kCommands, + arraysize(kCoords), GL_FLOAT, kCoords); + + glPathParameterfCHROMIUM(path, GL_PATH_STROKE_WIDTH_CHROMIUM, 5.0f); + glPathParameterfCHROMIUM(path, GL_PATH_MITER_LIMIT_CHROMIUM, 1.0f); + glPathParameterfCHROMIUM(path, GL_PATH_STROKE_BOUND_CHROMIUM, .02f); + glPathParameteriCHROMIUM(path, GL_PATH_JOIN_STYLE_CHROMIUM, + GL_ROUND_CHROMIUM); + glPathParameteriCHROMIUM(path, GL_PATH_END_CAPS_CHROMIUM, + GL_SQUARE_CHROMIUM); + } + + void VerifyTestPatternFill(float x, float y) { + static const float kFillCoords[] = { + 55.0f, 55.0f, 50.0f, 28.0f, 66.0f, 63.0f}; + static const uint8 kBlue[] = {0, 0, 255, 255}; + + for (size_t i = 0; i < arraysize(kFillCoords); i += 2) { + float fx = kFillCoords[i]; + float fy = kFillCoords[i + 1]; + + EXPECT_TRUE(GLTestHelper::CheckPixels(x + fx, y + fy, 1, 1, 0, kBlue)); + } + } + + void VerifyTestPatternBg(float x, float y) { + const float kBackgroundCoords[] = {80.0f, 80.0f, 20.0f, 20.0f, 90.0f, 1.0f}; + const uint8 kExpectedColor[] = {0, 0, 0, 0}; + + for (size_t i = 0; i < arraysize(kBackgroundCoords); i += 2) { + float bx = kBackgroundCoords[i]; + float by = kBackgroundCoords[i + 1]; + + EXPECT_TRUE( + GLTestHelper::CheckPixels(x + bx, y + by, 1, 1, 0, kExpectedColor)); + } + } + + void VerifyTestPatternStroke(float x, float y) { + // Inside the stroke we should have green. + const uint8 kGreen[] = {0, 255, 0, 255}; + EXPECT_TRUE(GLTestHelper::CheckPixels(x + 50, y + 53, 1, 1, 0, kGreen)); + EXPECT_TRUE(GLTestHelper::CheckPixels(x + 26, y + 76, 1, 1, 0, kGreen)); + + // Outside the path we should have black. + const uint8 black[] = {0, 0, 0, 0}; + EXPECT_TRUE(GLTestHelper::CheckPixels(x + 10, y + 10, 1, 1, 0, black)); + EXPECT_TRUE(GLTestHelper::CheckPixels(x + 80, y + 80, 1, 1, 0, black)); + } + + void TryAllDrawFunctions(GLuint path, GLenum expected_error) { + glStencilFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x7F); + EXPECT_EQ(expected_error, glGetError()); + + glStencilFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x7F); + EXPECT_EQ(expected_error, glGetError()); + + glStencilStrokePathCHROMIUM(path, 0x80, 0x80); + EXPECT_EQ(expected_error, glGetError()); + + glCoverFillPathCHROMIUM(path, GL_BOUNDING_BOX_CHROMIUM); + EXPECT_EQ(expected_error, glGetError()); + + glCoverStrokePathCHROMIUM(path, GL_BOUNDING_BOX_CHROMIUM); + EXPECT_EQ(expected_error, glGetError()); + + glStencilThenCoverStrokePathCHROMIUM(path, 0x80, 0x80, + GL_BOUNDING_BOX_CHROMIUM); + EXPECT_EQ(expected_error, glGetError()); + + glStencilThenCoverFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x7F, + GL_BOUNDING_BOX_CHROMIUM); + EXPECT_EQ(expected_error, glGetError()); + } + GLManager gl_; + GLint color_loc_; }; TEST_F(CHROMIUMPathRenderingTest, TestMatrix) { - if (!GLTestHelper::HasExtension("GL_CHROMIUM_path_rendering")) { + if (!GLTestHelper::HasExtension("GL_CHROMIUM_path_rendering")) return; - } + static const GLfloat kIdentityMatrix[16] = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; @@ -86,25 +235,388 @@ TEST_F(CHROMIUMPathRenderingTest, TestMatrix) { } TEST_F(CHROMIUMPathRenderingTest, TestMatrixErrors) { - if (!GLTestHelper::HasExtension("GL_CHROMIUM_path_rendering")) { + if (!GLTestHelper::HasExtension("GL_CHROMIUM_path_rendering")) return; - } + GLfloat mf[16]; memset(mf, 0, sizeof(mf)); - // This should fail. + glMatrixLoadfCHROMIUM(GL_PATH_MODELVIEW_CHROMIUM, mf); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + + glMatrixLoadIdentityCHROMIUM(GL_PATH_PROJECTION_CHROMIUM); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + + // Test that invalid matrix targets fail. glMatrixLoadfCHROMIUM(GL_PATH_MODELVIEW_CHROMIUM - 1, mf); EXPECT_EQ(static_cast<GLenum>(GL_INVALID_ENUM), glGetError()); - glMatrixLoadfCHROMIUM(GL_PATH_MODELVIEW_CHROMIUM, mf); + // Test that invalid matrix targets fail. + glMatrixLoadIdentityCHROMIUM(GL_PATH_PROJECTION_CHROMIUM + 1); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_ENUM), glGetError()); +} + +TEST_F(CHROMIUMPathRenderingTest, TestSimpleCalls) { + if (!GLTestHelper::HasExtension("GL_CHROMIUM_path_rendering")) + return; + + // This is unspecified in NV_path_rendering. + EXPECT_EQ(0u, glGenPathsCHROMIUM(0)); + + GLuint path = glGenPathsCHROMIUM(1); + EXPECT_NE(path, 0u); + glDeletePathsCHROMIUM(path, 1); EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); - // This should fail. - glMatrixLoadIdentityCHROMIUM(GL_PATH_PROJECTION_CHROMIUM + 1); + GLuint first_path = glGenPathsCHROMIUM(5); + EXPECT_NE(first_path, 0u); + glDeletePathsCHROMIUM(first_path, 5); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + + // Test deleting paths that are not actually allocated: + // "unused names in /paths/ are silently ignored". + first_path = glGenPathsCHROMIUM(5); + EXPECT_NE(first_path, 0u); + glDeletePathsCHROMIUM(first_path, 6); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + + GLsizei big_range = 0xffff; + // Setting big_range = std::numeric_limits<GLsizei>::max() should go through + // too, as far as NV_path_rendering is concerned. Current chromium side id + // allocator will use too much memory. + first_path = glGenPathsCHROMIUM(big_range); + EXPECT_NE(first_path, 0u); + glDeletePathsCHROMIUM(first_path, big_range); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + + // Test glIsPathCHROMIUM(). + path = glGenPathsCHROMIUM(1); + EXPECT_FALSE(glIsPathCHROMIUM(path)); + GLubyte commands[] = {GL_MOVE_TO_CHROMIUM, GL_CLOSE_PATH_CHROMIUM}; + GLfloat coords[] = {50.0f, 50.0f}; + glPathCommandsCHROMIUM(path, arraysize(commands), commands, arraysize(coords), + GL_FLOAT, coords); + EXPECT_TRUE(glIsPathCHROMIUM(path)); + glDeletePathsCHROMIUM(path, 1); + EXPECT_FALSE(glIsPathCHROMIUM(path)); +} + +TEST_F(CHROMIUMPathRenderingTest, TestGenDeleteErrors) { + if (!GLTestHelper::HasExtension("GL_CHROMIUM_path_rendering")) + return; + + // GenPaths / DeletePaths tests. + // std::numeric_limits<GLuint>::max() is wrong for GLsizei. + GLuint first_path = glGenPathsCHROMIUM(std::numeric_limits<GLuint>::max()); + EXPECT_EQ(first_path, 0u); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), glGetError()); + + first_path = glGenPathsCHROMIUM(-1); + EXPECT_EQ(first_path, 0u); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), glGetError()); + + glDeletePathsCHROMIUM(1, -5); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), glGetError()); + + first_path = glGenPathsCHROMIUM(-1); + EXPECT_EQ(first_path, 0u); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), glGetError()); + + // Test that delete with first_id and range such that first_id + range + // overflows the GLuint. Example: + // Range is 0x7fffffff. First id is X. Last id will be X + 0x7ffffffe. + // X = 0x80000001 would succeed, where as X = 0x80000002 would fail. + // To get 0x80000002, we need to allocate first 0x7fffffff and then + // 3 (0x80000000, 0x80000001 and 0x80000002). + // While not guaranteed by the API, we expect the implementation + // hands us deterministic ids. + first_path = glGenPathsCHROMIUM(std::numeric_limits<GLsizei>::max()); + EXPECT_EQ(first_path, 1u); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + + GLuint additional_paths = glGenPathsCHROMIUM(3); + EXPECT_EQ(additional_paths, + static_cast<GLuint>(std::numeric_limits<GLsizei>::max()) + 1u); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + + // Test that passing a range so big that it would overflow client_id + // + range - 1 check causes an error. + glDeletePathsCHROMIUM(additional_paths + 2u, + std::numeric_limits<GLsizei>::max()); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError()); + + // Cleanup the above allocations. Also test that passing max value still + // works. + glDeletePathsCHROMIUM(1, std::numeric_limits<GLsizei>::max()); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + glDeletePathsCHROMIUM(std::numeric_limits<GLsizei>::max(), + std::numeric_limits<GLsizei>::max()); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); +} + +TEST_F(CHROMIUMPathRenderingTest, TestPathParameterErrors) { + if (!GLTestHelper::HasExtension("GL_CHROMIUM_path_rendering")) + return; + + GLuint path = glGenPathsCHROMIUM(1); + // PathParameter*: Wrong value for the pname should fail. + glPathParameteriCHROMIUM(path, GL_PATH_JOIN_STYLE_CHROMIUM, GL_FLAT_CHROMIUM); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), glGetError()); + glPathParameterfCHROMIUM(path, GL_PATH_END_CAPS_CHROMIUM, + GL_MITER_REVERT_CHROMIUM); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), glGetError()); + + // PathParameter*: Wrong floating-point value should fail. + glPathParameterfCHROMIUM(path, GL_PATH_STROKE_WIDTH_CHROMIUM, -0.1f); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), glGetError()); + glPathParameterfCHROMIUM(path, GL_PATH_MITER_LIMIT_CHROMIUM, + std::numeric_limits<float>::quiet_NaN()); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), glGetError()); + glPathParameterfCHROMIUM(path, GL_PATH_MITER_LIMIT_CHROMIUM, + std::numeric_limits<float>::infinity()); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), glGetError()); + + // PathParameter*: Wrong pname should fail. + glPathParameteriCHROMIUM(path, GL_PATH_STROKE_WIDTH_CHROMIUM - 1, 5); EXPECT_EQ(static_cast<GLenum>(GL_INVALID_ENUM), glGetError()); + glDeletePathsCHROMIUM(path, 1); +} - glMatrixLoadIdentityCHROMIUM(GL_PATH_PROJECTION_CHROMIUM); +TEST_F(CHROMIUMPathRenderingTest, TestPathObjectState) { + if (!GLTestHelper::HasExtension("GL_CHROMIUM_path_rendering")) + return; + + glViewport(0, 0, kResolution, kResolution); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glStencilMask(0xffffffff); + glClearStencil(0); + glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + glPathStencilFuncCHROMIUM(GL_ALWAYS, 0, 0xFF); + glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO); + + // Test that trying to draw non-existing paths does not produce errors or + // results. + GLuint non_existing_paths[] = {0, 55, 74744}; + for (auto& p : non_existing_paths) { + EXPECT_FALSE(glIsPathCHROMIUM(p)); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + TryAllDrawFunctions(p, GL_NO_ERROR); + } + + // Path name marked as used but without path object state causes + // a GL error upon any draw command. + GLuint path = glGenPathsCHROMIUM(1); + EXPECT_FALSE(glIsPathCHROMIUM(path)); + TryAllDrawFunctions(path, GL_INVALID_OPERATION); + glDeletePathsCHROMIUM(path, 1); + + // Document a bit of an inconsistency: path name marked as used but without + // path object state causes a GL error upon any draw command (tested above). + // Path name that had path object state, but then was "cleared", still has a + // path object state, even though the state is empty. + path = glGenPathsCHROMIUM(1); + EXPECT_FALSE(glIsPathCHROMIUM(path)); + GLubyte commands[] = {GL_MOVE_TO_CHROMIUM, GL_CLOSE_PATH_CHROMIUM}; + GLfloat coords[] = {50.0f, 50.0f}; + glPathCommandsCHROMIUM(path, arraysize(commands), commands, arraysize(coords), + GL_FLOAT, coords); + EXPECT_TRUE(glIsPathCHROMIUM(path)); + glPathCommandsCHROMIUM(path, 0, NULL, 0, GL_FLOAT, NULL); + EXPECT_TRUE(glIsPathCHROMIUM(path)); // The surprise. + TryAllDrawFunctions(path, GL_NO_ERROR); + glDeletePathsCHROMIUM(path, 1); + + // Document a bit of an inconsistency: "clearing" a used path name causes + // path to acquire state. + path = glGenPathsCHROMIUM(1); + EXPECT_FALSE(glIsPathCHROMIUM(path)); + glPathCommandsCHROMIUM(path, 0, NULL, 0, GL_FLOAT, NULL); + EXPECT_TRUE(glIsPathCHROMIUM(path)); // The surprise. + glDeletePathsCHROMIUM(path, 1); + + // Make sure nothing got drawn by the drawing commands that should not produce + // anything. + const uint8 black[] = {0, 0, 0, 0}; + EXPECT_TRUE( + GLTestHelper::CheckPixels(0, 0, kResolution, kResolution, 0, black)); +} + +TEST_F(CHROMIUMPathRenderingTest, TestUnnamedPathsErrors) { + if (!GLTestHelper::HasExtension("GL_CHROMIUM_path_rendering")) + return; + + // Unnamed paths: Trying to create a path object with non-existing path name + // produces error. (Not a error in real NV_path_rendering). + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + GLubyte commands[] = {GL_MOVE_TO_CHROMIUM, GL_CLOSE_PATH_CHROMIUM}; + GLfloat coords[] = {50.0f, 50.0f}; + glPathCommandsCHROMIUM(555, arraysize(commands), commands, arraysize(coords), + GL_FLOAT, coords); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError()); + + // PathParameter*: Using non-existing path object produces error. + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + glPathParameterfCHROMIUM(555, GL_PATH_STROKE_WIDTH_CHROMIUM, 5.0f); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError()); + + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + glPathParameteriCHROMIUM(555, GL_PATH_JOIN_STYLE_CHROMIUM, GL_ROUND_CHROMIUM); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError()); +} + +TEST_F(CHROMIUMPathRenderingTest, TestPathCommandsErrors) { + if (!GLTestHelper::HasExtension("GL_CHROMIUM_path_rendering")) + return; + + static const GLenum kInvalidCoordType = GL_NONE; + + GLuint path = glGenPathsCHROMIUM(1); + GLubyte commands[] = {GL_MOVE_TO_CHROMIUM, GL_CLOSE_PATH_CHROMIUM}; + GLfloat coords[] = {50.0f, 50.0f}; + + glPathCommandsCHROMIUM(path, arraysize(commands), commands, -4, GL_FLOAT, + coords); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), glGetError()); + + glPathCommandsCHROMIUM(path, -1, commands, arraysize(coords), GL_FLOAT, + coords); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), glGetError()); + + glPathCommandsCHROMIUM(path, arraysize(commands), commands, arraysize(coords), + kInvalidCoordType, coords); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_ENUM), glGetError()); + + // These can not distinquish between the check that should fail them. + // This should fail due to coord count * float size overflow. + glPathCommandsCHROMIUM(path, arraysize(commands), commands, + std::numeric_limits<GLsizei>::max(), GL_FLOAT, coords); + // This should fail due to cmd count + coord count * short size. + glPathCommandsCHROMIUM(path, arraysize(commands), commands, + std::numeric_limits<GLsizei>::max(), GL_SHORT, coords); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError()); + + glDeletePathsCHROMIUM(path, 1); +} + +TEST_F(CHROMIUMPathRenderingTest, TestPathRenderingInvalidArgs) { + if (!GLTestHelper::HasExtension("GL_CHROMIUM_path_rendering")) + return; + + GLuint path = glGenPathsCHROMIUM(1); + glPathCommandsCHROMIUM(path, 0, NULL, 0, GL_FLOAT, NULL); + + // Verify that normal calls work. + glStencilFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x7F); EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + glStencilThenCoverFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x7F, + GL_BOUNDING_BOX_CHROMIUM); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + + // Using invalid fill mode causes INVALID_ENUM. + glStencilFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM - 1, 0x7F); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_ENUM), glGetError()); + glStencilThenCoverFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM - 1, 0x7F, + GL_BOUNDING_BOX_CHROMIUM); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_ENUM), glGetError()); + + // Using invalid cover mode causes INVALID_ENUM. + glCoverFillPathCHROMIUM(path, GL_CONVEX_HULL_CHROMIUM - 1); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_ENUM), glGetError()); + glStencilThenCoverFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x7F, + GL_BOUNDING_BOX_CHROMIUM + 1); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_ENUM), glGetError()); + + // Using mask+1 not being power of two causes INVALID_VALUE with up/down fill + // mode. + glStencilFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x40); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), glGetError()); + glStencilThenCoverFillPathCHROMIUM(path, GL_COUNT_DOWN_CHROMIUM, 12, + GL_BOUNDING_BOX_CHROMIUM); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), glGetError()); + + glDeletePathsCHROMIUM(path, 1); +} + +// Tests that drawing with CHROMIUM_path_rendering functions work. +TEST_F(CHROMIUMPathRenderingTest, TestPathRendering) { + if (!GLTestHelper::HasExtension("GL_CHROMIUM_path_rendering")) + return; + + static const float kBlue[] = {0.0f, 0.0f, 1.0f, 1.0f}; + static const float kGreen[] = {0.0f, 1.0f, 0.0f, 1.0f}; + + SetupStateForTestPattern(); + + GLuint path = glGenPathsCHROMIUM(1); + SetupPathStateForTestPattern(path); + + // Do the stencil fill, cover fill, stencil stroke, cover stroke + // in unconventional order: + // 1) stencil the stroke in stencil high bit + // 2) stencil the fill in low bits + // 3) cover the fill + // 4) cover the stroke + // This is done to check that glPathStencilFunc works, eg the mask + // goes through. Stencil func is not tested ATM, for simplicity. + + glPathStencilFuncCHROMIUM(GL_ALWAYS, 0, 0xFF); + glStencilStrokePathCHROMIUM(path, 0x80, 0x80); + + glPathStencilFuncCHROMIUM(GL_ALWAYS, 0, 0x7F); + glStencilFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x7F); + + glStencilFunc(GL_LESS, 0, 0x7F); + glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO); + glUniform4fv(color_loc_, 1, kBlue); + glCoverFillPathCHROMIUM(path, GL_BOUNDING_BOX_CHROMIUM); + + glStencilFunc(GL_EQUAL, 0x80, 0x80); + glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO); + glUniform4fv(color_loc_, 1, kGreen); + glCoverStrokePathCHROMIUM(path, GL_CONVEX_HULL_CHROMIUM); + + glDeletePathsCHROMIUM(path, 1); + + // Verify the image. + VerifyTestPatternFill(0.0f, 0.0f); + VerifyTestPatternBg(0.0f, 0.0f); + VerifyTestPatternStroke(0.0f, 0.0f); +} + +// Tests that drawing with CHROMIUM_path_rendering +// StencilThenCover{Stroke,Fill}Path functions work. +TEST_F(CHROMIUMPathRenderingTest, TestPathRenderingThenFunctions) { + if (!GLTestHelper::HasExtension("GL_CHROMIUM_path_rendering")) + return; + + static float kBlue[] = {0.0f, 0.0f, 1.0f, 1.0f}; + static float kGreen[] = {0.0f, 1.0f, 0.0f, 1.0f}; + + SetupStateForTestPattern(); + + GLuint path = glGenPathsCHROMIUM(1); + SetupPathStateForTestPattern(path); + + glPathStencilFuncCHROMIUM(GL_ALWAYS, 0, 0xFF); + glStencilFunc(GL_EQUAL, 0x80, 0x80); + glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO); + glUniform4fv(color_loc_, 1, kGreen); + glStencilThenCoverStrokePathCHROMIUM(path, 0x80, 0x80, + GL_BOUNDING_BOX_CHROMIUM); + + glPathStencilFuncCHROMIUM(GL_ALWAYS, 0, 0x7F); + glStencilFunc(GL_LESS, 0, 0x7F); + glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO); + glUniform4fv(color_loc_, 1, kBlue); + glStencilThenCoverFillPathCHROMIUM(path, GL_COUNT_UP_CHROMIUM, 0x7F, + GL_CONVEX_HULL_CHROMIUM); + + glDeletePathsCHROMIUM(path, 1); + + // Verify the image. + VerifyTestPatternFill(0.0f, 0.0f); + VerifyTestPatternBg(0.0f, 0.0f); + VerifyTestPatternStroke(0.0f, 0.0f); } } // namespace gpu |