|  | // Copyright 2014 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "gpu/command_buffer/service/gles2_cmd_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::kUnknownCommand, ExecuteImmediateCmd(cmd, sizeof(temp))); | 
|  | } | 
|  | { | 
|  | cmds::MatrixLoadIdentityCHROMIUM cmd; | 
|  | cmd.Init(GL_PATH_PROJECTION_CHROMIUM); | 
|  | EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); | 
|  | } | 
|  | { | 
|  | cmds::GenPathsCHROMIUM cmd; | 
|  | cmd.Init(0, 0); | 
|  | EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); | 
|  | } | 
|  | { | 
|  | cmds::DeletePathsCHROMIUM cmd; | 
|  | cmd.Init(0, 0); | 
|  | EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); | 
|  | } | 
|  | { | 
|  | cmds::IsPathCHROMIUM cmd; | 
|  | cmd.Init(kClientPathId, shared_memory_id_, shared_memory_offset_); | 
|  | EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); | 
|  | } | 
|  | { | 
|  | cmds::PathCommandsCHROMIUM cmd; | 
|  | cmd.Init(kClientPathId, 0, 0, 0, 0, GL_FLOAT, 0, 0); | 
|  | EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); | 
|  | } | 
|  | { | 
|  | cmds::PathParameterfCHROMIUM cmd; | 
|  | cmd.Init(kClientPathId, GL_PATH_STROKE_WIDTH_CHROMIUM, 1.0f); | 
|  | EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); | 
|  | } | 
|  | { | 
|  | cmds::PathParameteriCHROMIUM cmd; | 
|  | cmd.Init(kClientPathId, GL_PATH_STROKE_WIDTH_CHROMIUM, 1); | 
|  | EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); | 
|  | } | 
|  | { | 
|  | cmds::PathStencilFuncCHROMIUM cmd; | 
|  | cmd.Init(GL_NEVER, 2, 3); | 
|  | EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); | 
|  | } | 
|  | { | 
|  | cmds::StencilFillPathCHROMIUM cmd; | 
|  | cmd.Init(kClientPathId, GL_COUNT_UP_CHROMIUM, 1); | 
|  | EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); | 
|  | } | 
|  | { | 
|  | cmds::StencilStrokePathCHROMIUM cmd; | 
|  | cmd.Init(kClientPathId, 1, 2); | 
|  | EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); | 
|  | } | 
|  | { | 
|  | cmds::CoverFillPathCHROMIUM cmd; | 
|  | cmd.Init(kClientPathId, GL_BOUNDING_BOX_CHROMIUM); | 
|  | EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); | 
|  | } | 
|  | { | 
|  | cmds::CoverStrokePathCHROMIUM cmd; | 
|  | cmd.Init(kClientPathId, GL_BOUNDING_BOX_CHROMIUM); | 
|  | EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); | 
|  | } | 
|  | { | 
|  | cmds::StencilThenCoverFillPathCHROMIUM cmd; | 
|  | cmd.Init(kClientPathId, GL_COUNT_UP_CHROMIUM, 1, GL_BOUNDING_BOX_CHROMIUM); | 
|  | EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); | 
|  | } | 
|  | { | 
|  | cmds::StencilThenCoverStrokePathCHROMIUM cmd; | 
|  | cmd.Init(kClientPathId, 1, 2, GL_BOUNDING_BOX_CHROMIUM); | 
|  | EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); | 
|  | } | 
|  | { | 
|  | cmds::StencilFillPathInstancedCHROMIUM cmd; | 
|  | GLuint* paths = GetSharedMemoryAs<GLuint*>(); | 
|  | paths[0] = kClientPathId; | 
|  | cmd.Init(1, GL_UNSIGNED_INT, shared_memory_id_, shared_memory_offset_, 0, | 
|  | GL_COUNT_UP_CHROMIUM, 1, GL_NONE, 0, 0); | 
|  | EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); | 
|  | } | 
|  | { | 
|  | cmds::StencilStrokePathInstancedCHROMIUM cmd; | 
|  | GLuint* paths = GetSharedMemoryAs<GLuint*>(); | 
|  | paths[0] = kClientPathId; | 
|  | cmd.Init(1, GL_UNSIGNED_INT, shared_memory_id_, shared_memory_offset_, 0, | 
|  | 0x80, 0x80, GL_NONE, 0, 0); | 
|  | EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); | 
|  | } | 
|  | { | 
|  | cmds::CoverFillPathInstancedCHROMIUM cmd; | 
|  | GLuint* paths = GetSharedMemoryAs<GLuint*>(); | 
|  | paths[0] = kClientPathId; | 
|  | cmd.Init(1, GL_UNSIGNED_INT, shared_memory_id_, shared_memory_offset_, 0, | 
|  | GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM, GL_NONE, 0, 0); | 
|  | EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); | 
|  | } | 
|  | { | 
|  | cmds::CoverStrokePathInstancedCHROMIUM cmd; | 
|  | GLuint* paths = GetSharedMemoryAs<GLuint*>(); | 
|  | paths[0] = kClientPathId; | 
|  | cmd.Init(1, GL_UNSIGNED_INT, shared_memory_id_, shared_memory_offset_, 0, | 
|  | GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM, GL_NONE, 0, 0); | 
|  | EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); | 
|  | } | 
|  | { | 
|  | cmds::StencilThenCoverFillPathInstancedCHROMIUM cmd; | 
|  | GLuint* paths = GetSharedMemoryAs<GLuint*>(); | 
|  | paths[0] = kClientPathId; | 
|  | cmd.Init(1, GL_UNSIGNED_INT, shared_memory_id_, shared_memory_offset_, 0, | 
|  | GL_COUNT_UP_CHROMIUM, 1, | 
|  | GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM, GL_NONE, 0, 0); | 
|  | EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); | 
|  | } | 
|  | { | 
|  | cmds::StencilThenCoverStrokePathInstancedCHROMIUM cmd; | 
|  | GLuint* paths = GetSharedMemoryAs<GLuint*>(); | 
|  | paths[0] = kClientPathId; | 
|  | cmd.Init(1, GL_UNSIGNED_INT, shared_memory_id_, shared_memory_offset_, 0, | 
|  | 0x80, 0x80, GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM, GL_NONE, 0, | 
|  | 0); | 
|  | EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); | 
|  | } | 
|  | { | 
|  | cmds::BindFragmentInputLocationCHROMIUMBucket cmd; | 
|  | const uint32 kBucketId = 123; | 
|  | const GLint kLocation = 2; | 
|  | const char* kName = "testing"; | 
|  | SetBucketAsCString(kBucketId, kName); | 
|  | cmd.Init(client_program_id_, kLocation, kBucketId); | 
|  | EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); | 
|  | } | 
|  | { | 
|  | cmds::ProgramPathFragmentInputGenCHROMIUM cmd; | 
|  | const GLint kLocation = 2; | 
|  | cmd.Init(client_program_id_, kLocation, 0, GL_NONE, 0, 0); | 
|  | EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); | 
|  | } | 
|  | } | 
|  |  | 
|  | class GLES2DecoderTestWithCHROMIUMPathRendering : public GLES2DecoderTest { | 
|  | public: | 
|  | GLES2DecoderTestWithCHROMIUMPathRendering() : client_path_id_(125) {} | 
|  |  | 
|  | void SetUp() override { | 
|  | InitState init; | 
|  | init.gl_version = "opengl es 3.1"; | 
|  | init.has_alpha = true; | 
|  | init.has_depth = true; | 
|  | init.request_alpha = true; | 
|  | init.request_depth = true; | 
|  | init.bind_generates_resource = true; | 
|  | init.extensions = "GL_NV_path_rendering"; | 
|  | 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)); | 
|  |  | 
|  | // The tests use client_path_id_ to test all sorts of drawing. The NVPR API | 
|  | // behaves differently with a path name that is "used" but not which does | 
|  | // not "allocate path object state" and a path name that is a name of a real | 
|  | // path object. The drawing with former causes GL error while latter works | 
|  | // ok, even if there is nothing in the actual path object. To remain | 
|  | // compatible with the API, we allocate path object state even when using | 
|  | // the mock API. | 
|  | EXPECT_CALL(*gl_, | 
|  | PathCommandsNV(kServicePathId, 0, NULL, 0, GL_FLOAT, NULL)) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::PathCommandsCHROMIUM pcmd; | 
|  | pcmd.Init(client_path_id_, 0, 0, 0, 0, GL_FLOAT, 0, 0); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(pcmd)); | 
|  | } | 
|  |  | 
|  | protected: | 
|  | template <typename TypeParam> | 
|  | void TestPathCommandsCHROMIUMCoordTypes(); | 
|  |  | 
|  | struct InstancedTestcase { | 
|  | GLsizei num_paths; | 
|  | GLenum path_name_type; | 
|  | const void* paths; | 
|  | GLuint path_base; | 
|  | GLenum fill_mode; | 
|  | GLuint reference; | 
|  | GLuint mask; | 
|  | GLenum transform_type; | 
|  | const GLfloat* transform_values; | 
|  | size_t sizeof_paths;             // Used for copying to shm buffer. | 
|  | size_t sizeof_transform_values;  // Used for copying to shm buffer. | 
|  | error::Error expected_error; | 
|  | GLint expected_gl_error; | 
|  | bool expect_gl_call; | 
|  | }; | 
|  |  | 
|  | void CallAllInstancedCommands(const InstancedTestcase& testcase) { | 
|  | // Note: for testcases that expect a call, We do not compare the 'paths' | 
|  | // array during EXPECT_CALL due to it being void*. Instead, we rely on the | 
|  | // fact that if the path base was not added correctly, the paths wouldn't | 
|  | // exists and the call wouldn't come through. | 
|  |  | 
|  | bool copy_paths = false;  // Paths are copied for each call that has paths, | 
|  | // since the implementation modifies the memory | 
|  | // area. | 
|  | void* paths = NULL; | 
|  | uint32 paths_shm_id = 0; | 
|  | uint32 paths_shm_offset = 0; | 
|  | GLfloat* transforms = NULL; | 
|  | uint32 transforms_shm_id = 0; | 
|  | uint32 transforms_shm_offset = 0; | 
|  |  | 
|  | if (testcase.transform_values) { | 
|  | transforms = GetSharedMemoryAs<GLfloat*>(); | 
|  | transforms_shm_id = shared_memory_id_; | 
|  | transforms_shm_offset = shared_memory_offset_; | 
|  | memcpy(transforms, testcase.transform_values, | 
|  | testcase.sizeof_transform_values); | 
|  | } else { | 
|  | DCHECK(testcase.sizeof_transform_values == 0); | 
|  | } | 
|  | if (testcase.paths) { | 
|  | paths = | 
|  | GetSharedMemoryAsWithOffset<void*>(testcase.sizeof_transform_values); | 
|  | paths_shm_id = shared_memory_id_; | 
|  | paths_shm_offset = | 
|  | shared_memory_offset_ + testcase.sizeof_transform_values; | 
|  | copy_paths = true; | 
|  | } else { | 
|  | DCHECK(testcase.sizeof_paths == 0); | 
|  | } | 
|  |  | 
|  | if (testcase.expect_gl_call) { | 
|  | EXPECT_CALL(*gl_, StencilFillPathInstancedNV( | 
|  | testcase.num_paths, GL_UNSIGNED_INT, _, 0, | 
|  | testcase.fill_mode, testcase.mask, | 
|  | testcase.transform_type, transforms)) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | if (copy_paths) { | 
|  | memcpy(paths, testcase.paths, testcase.sizeof_paths); | 
|  | } | 
|  | { | 
|  | cmds::StencilFillPathInstancedCHROMIUM sfi_cmd; | 
|  | sfi_cmd.Init(testcase.num_paths, testcase.path_name_type, paths_shm_id, | 
|  | paths_shm_offset, testcase.path_base, testcase.fill_mode, | 
|  | testcase.mask, testcase.transform_type, transforms_shm_id, | 
|  | transforms_shm_offset); | 
|  | EXPECT_EQ(testcase.expected_error, ExecuteCmd(sfi_cmd)); | 
|  | EXPECT_EQ(testcase.expected_gl_error, GetGLError()); | 
|  | } | 
|  |  | 
|  | if (testcase.expect_gl_call) { | 
|  | EXPECT_CALL(*gl_, StencilStrokePathInstancedNV( | 
|  | testcase.num_paths, GL_UNSIGNED_INT, _, 0, | 
|  | testcase.reference, testcase.mask, | 
|  | testcase.transform_type, transforms)) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | if (copy_paths) { | 
|  | memcpy(paths, testcase.paths, testcase.sizeof_paths); | 
|  | } | 
|  | { | 
|  | cmds::StencilStrokePathInstancedCHROMIUM ssi_cmd; | 
|  | ssi_cmd.Init(testcase.num_paths, testcase.path_name_type, paths_shm_id, | 
|  | paths_shm_offset, testcase.path_base, testcase.reference, | 
|  | testcase.mask, testcase.transform_type, transforms_shm_id, | 
|  | transforms_shm_offset); | 
|  | EXPECT_EQ(testcase.expected_error, ExecuteCmd(ssi_cmd)); | 
|  | EXPECT_EQ(testcase.expected_gl_error, GetGLError()); | 
|  | } | 
|  |  | 
|  | if (testcase.expect_gl_call) { | 
|  | EXPECT_CALL(*gl_, CoverFillPathInstancedNV( | 
|  | testcase.num_paths, GL_UNSIGNED_INT, _, 0, | 
|  | GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV, | 
|  | testcase.transform_type, transforms)) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | if (copy_paths) { | 
|  | memcpy(paths, testcase.paths, testcase.sizeof_paths); | 
|  | } | 
|  | { | 
|  | cmds::CoverFillPathInstancedCHROMIUM cfi_cmd; | 
|  | cfi_cmd.Init(testcase.num_paths, testcase.path_name_type, paths_shm_id, | 
|  | paths_shm_offset, testcase.path_base, | 
|  | GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM, | 
|  | testcase.transform_type, transforms_shm_id, | 
|  | transforms_shm_offset); | 
|  | EXPECT_EQ(testcase.expected_error, ExecuteCmd(cfi_cmd)); | 
|  | EXPECT_EQ(testcase.expected_gl_error, GetGLError()); | 
|  | } | 
|  | if (testcase.expect_gl_call) { | 
|  | EXPECT_CALL(*gl_, CoverStrokePathInstancedNV( | 
|  | testcase.num_paths, GL_UNSIGNED_INT, _, 0, | 
|  | GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV, | 
|  | testcase.transform_type, transforms)) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | if (copy_paths) { | 
|  | memcpy(paths, testcase.paths, testcase.sizeof_paths); | 
|  | } | 
|  |  | 
|  | { | 
|  | cmds::CoverStrokePathInstancedCHROMIUM csi_cmd; | 
|  | csi_cmd.Init(testcase.num_paths, testcase.path_name_type, paths_shm_id, | 
|  | paths_shm_offset, testcase.path_base, | 
|  | GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM, | 
|  | testcase.transform_type, transforms_shm_id, | 
|  | transforms_shm_offset); | 
|  | EXPECT_EQ(testcase.expected_error, ExecuteCmd(csi_cmd)); | 
|  | EXPECT_EQ(testcase.expected_gl_error, GetGLError()); | 
|  | } | 
|  |  | 
|  | if (testcase.expect_gl_call) { | 
|  | EXPECT_CALL(*gl_, StencilThenCoverFillPathInstancedNV( | 
|  | testcase.num_paths, GL_UNSIGNED_INT, _, 0, | 
|  | testcase.fill_mode, testcase.mask, | 
|  | GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV, | 
|  | testcase.transform_type, transforms)) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | if (copy_paths) { | 
|  | memcpy(paths, testcase.paths, testcase.sizeof_paths); | 
|  | } | 
|  | { | 
|  | cmds::StencilThenCoverFillPathInstancedCHROMIUM stcfi_cmd; | 
|  | stcfi_cmd.Init(testcase.num_paths, testcase.path_name_type, paths_shm_id, | 
|  | paths_shm_offset, testcase.path_base, testcase.fill_mode, | 
|  | testcase.mask, GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM, | 
|  | testcase.transform_type, transforms_shm_id, | 
|  | transforms_shm_offset); | 
|  | EXPECT_EQ(testcase.expected_error, ExecuteCmd(stcfi_cmd)); | 
|  | EXPECT_EQ(testcase.expected_gl_error, GetGLError()); | 
|  | } | 
|  |  | 
|  | if (testcase.expect_gl_call) { | 
|  | EXPECT_CALL(*gl_, StencilThenCoverStrokePathInstancedNV( | 
|  | testcase.num_paths, GL_UNSIGNED_INT, _, 0, | 
|  | testcase.reference, testcase.mask, | 
|  | GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV, | 
|  | testcase.transform_type, transforms)) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | if (copy_paths) { | 
|  | memcpy(paths, testcase.paths, testcase.sizeof_paths); | 
|  | } | 
|  | { | 
|  | cmds::StencilThenCoverStrokePathInstancedCHROMIUM stcsi_cmd; | 
|  | stcsi_cmd.Init(testcase.num_paths, testcase.path_name_type, paths_shm_id, | 
|  | paths_shm_offset, testcase.path_base, testcase.reference, | 
|  | testcase.mask, GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM, | 
|  | testcase.transform_type, transforms_shm_id, | 
|  | transforms_shm_offset); | 
|  | EXPECT_EQ(testcase.expected_error, ExecuteCmd(stcsi_cmd)); | 
|  | EXPECT_EQ(testcase.expected_gl_error, GetGLError()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void CallAllInstancedCommandsWithInvalidSHM(GLsizei num_paths, | 
|  | const GLuint* paths, | 
|  | GLuint* paths_shm, | 
|  | uint32 paths_shm_id, | 
|  | uint32 paths_shm_offset, | 
|  | uint32 transforms_shm_id, | 
|  | uint32 transforms_shm_offset) { | 
|  | const GLuint kPathBase = 0; | 
|  | const GLenum kFillMode = GL_INVERT; | 
|  | const GLuint kMask = 0x80; | 
|  | const GLuint kReference = 0xFF; | 
|  | const GLuint kTransformType = GL_AFFINE_3D_CHROMIUM; | 
|  | memcpy(paths_shm, paths, sizeof(GLuint) * num_paths); | 
|  | { | 
|  | cmds::StencilFillPathInstancedCHROMIUM sfi_cmd; | 
|  | sfi_cmd.Init(num_paths, GL_UNSIGNED_INT, paths_shm_id, paths_shm_offset, | 
|  | kPathBase, kFillMode, kMask, kTransformType, | 
|  | transforms_shm_id, transforms_shm_offset); | 
|  | EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(sfi_cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | } | 
|  | memcpy(paths_shm, paths, sizeof(GLuint) * num_paths); | 
|  | { | 
|  | cmds::StencilStrokePathInstancedCHROMIUM ssi_cmd; | 
|  | ssi_cmd.Init(num_paths, GL_UNSIGNED_INT, paths_shm_id, paths_shm_offset, | 
|  | kPathBase, kReference, kMask, kTransformType, | 
|  | transforms_shm_id, transforms_shm_offset); | 
|  | EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(ssi_cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | } | 
|  | memcpy(paths_shm, paths, sizeof(GLuint) * num_paths); | 
|  | { | 
|  | cmds::CoverFillPathInstancedCHROMIUM cfi_cmd; | 
|  | cfi_cmd.Init(num_paths, GL_UNSIGNED_INT, paths_shm_id, paths_shm_offset, | 
|  | kPathBase, GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM, | 
|  | kTransformType, transforms_shm_id, transforms_shm_offset); | 
|  | EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cfi_cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | } | 
|  | memcpy(paths_shm, paths, sizeof(GLuint) * num_paths); | 
|  | { | 
|  | cmds::CoverStrokePathInstancedCHROMIUM csi_cmd; | 
|  | csi_cmd.Init(num_paths, GL_UNSIGNED_INT, paths_shm_id, paths_shm_offset, | 
|  | kPathBase, GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM, | 
|  | kTransformType, transforms_shm_id, transforms_shm_offset); | 
|  | EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(csi_cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | } | 
|  | memcpy(paths_shm, paths, sizeof(GLuint) * num_paths); | 
|  | { | 
|  | cmds::StencilThenCoverFillPathInstancedCHROMIUM stcfi_cmd; | 
|  | stcfi_cmd.Init(num_paths, GL_UNSIGNED_INT, paths_shm_id, paths_shm_offset, | 
|  | kPathBase, kFillMode, kMask, | 
|  | GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM, kTransformType, | 
|  | transforms_shm_id, transforms_shm_offset); | 
|  | EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(stcfi_cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | } | 
|  | memcpy(paths_shm, paths, sizeof(GLuint) * num_paths); | 
|  | { | 
|  | cmds::StencilThenCoverStrokePathInstancedCHROMIUM stcsi_cmd; | 
|  | stcsi_cmd.Init(num_paths, GL_UNSIGNED_INT, paths_shm_id, paths_shm_offset, | 
|  | kPathBase, kReference, kMask, | 
|  | GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM, kTransformType, | 
|  | transforms_shm_id, transforms_shm_offset); | 
|  | EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(stcsi_cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | } | 
|  | } | 
|  |  | 
|  | GLuint client_path_id_; | 
|  | static const GLuint kServicePathId = 311; | 
|  | }; | 
|  |  | 
|  | INSTANTIATE_TEST_CASE_P(Service, | 
|  | GLES2DecoderTestWithCHROMIUMPathRendering, | 
|  | ::testing::Bool()); | 
|  |  | 
|  | class GLES2DecoderTestWithBlendEquationAdvanced : public GLES2DecoderTest { | 
|  | public: | 
|  | GLES2DecoderTestWithBlendEquationAdvanced() {} | 
|  | void SetUp() override { | 
|  | InitState init; | 
|  | init.gl_version = "opengl es 2.0"; | 
|  | init.has_alpha = true; | 
|  | init.has_depth = true; | 
|  | init.request_alpha = true; | 
|  | init.request_depth = true; | 
|  | init.bind_generates_resource = true; | 
|  | init.extensions = "GL_KHR_blend_equation_advanced"; | 
|  | InitDecoder(init); | 
|  | } | 
|  | }; | 
|  |  | 
|  | INSTANTIATE_TEST_CASE_P(Service, | 
|  | GLES2DecoderTestWithBlendEquationAdvanced, | 
|  | ::testing::Bool()); | 
|  |  | 
|  | class GLES2DecoderTestWithEXTMultisampleCompatibility | 
|  | : public GLES2DecoderTest { | 
|  | public: | 
|  | GLES2DecoderTestWithEXTMultisampleCompatibility() {} | 
|  |  | 
|  | void SetUp() override { | 
|  | InitState init; | 
|  | init.gl_version = "opengl es 3.1"; | 
|  | init.has_alpha = true; | 
|  | init.has_depth = true; | 
|  | init.request_alpha = true; | 
|  | init.request_depth = true; | 
|  | init.bind_generates_resource = true; | 
|  | init.extensions = "GL_EXT_multisample_compatibility "; | 
|  | InitDecoder(init); | 
|  | } | 
|  | }; | 
|  | INSTANTIATE_TEST_CASE_P(Service, | 
|  | GLES2DecoderTestWithEXTMultisampleCompatibility, | 
|  | ::testing::Bool()); | 
|  |  | 
|  | class GLES2DecoderTestWithBlendFuncExtended : public GLES2DecoderTest { | 
|  | public: | 
|  | GLES2DecoderTestWithBlendFuncExtended() {} | 
|  | void SetUp() override { | 
|  | InitState init; | 
|  | init.gl_version = "opengl es 3.0"; | 
|  | init.has_alpha = true; | 
|  | init.has_depth = true; | 
|  | init.request_alpha = true; | 
|  | init.request_depth = true; | 
|  | init.bind_generates_resource = true; | 
|  | init.extensions = "GL_EXT_blend_func_extended"; | 
|  | InitDecoder(init); | 
|  | } | 
|  | }; | 
|  | INSTANTIATE_TEST_CASE_P(Service, | 
|  | GLES2DecoderTestWithBlendFuncExtended, | 
|  | ::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 id 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>(); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, | 
|  | StencilXFillPathInstancedCHROMIUMInvalidArgs) { | 
|  | cmds::StencilFillPathInstancedCHROMIUM sfi_cmd; | 
|  | cmds::StencilThenCoverFillPathInstancedCHROMIUM stcfi_cmd; | 
|  |  | 
|  | const GLuint kPaths[] = {client_path_id_, client_path_id_ + 5, | 
|  | client_path_id_, client_path_id_ + 18}; | 
|  | const GLsizei kPathCount = arraysize(kPaths); | 
|  |  | 
|  | struct { | 
|  | GLenum fill_mode; | 
|  | GLuint mask; | 
|  | GLint expected_error; | 
|  | } testcases[] = { | 
|  | // Using invalid fill mode produces invalid enum. | 
|  | {GL_COUNT_UP_CHROMIUM - 1, 0x7F, GL_INVALID_ENUM}, | 
|  | {GL_COUNT_DOWN_CHROMIUM + 1, 0x7F, GL_INVALID_ENUM}, | 
|  | // Using /mask/+1 which is not power of two produces invalid value. | 
|  | {GL_COUNT_UP_CHROMIUM, 0x80, GL_INVALID_VALUE}, | 
|  | {GL_COUNT_DOWN_CHROMIUM, 4, GL_INVALID_VALUE}}; | 
|  |  | 
|  | GLuint* paths = GetSharedMemoryAs<GLuint*>(); | 
|  |  | 
|  | for (size_t i = 0; i < arraysize(testcases); ++i) { | 
|  | memcpy(paths, kPaths, sizeof(kPaths)); | 
|  | sfi_cmd.Init(kPathCount, GL_UNSIGNED_INT, shared_memory_id_, | 
|  | shared_memory_offset_, 0, testcases[i].fill_mode, | 
|  | testcases[i].mask, GL_NONE, 0, 0); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(sfi_cmd)); | 
|  | EXPECT_EQ(testcases[i].expected_error, GetGLError()); | 
|  |  | 
|  | memcpy(paths, kPaths, sizeof(kPaths)); | 
|  | stcfi_cmd.Init(kPathCount, GL_UNSIGNED_INT, shared_memory_id_, | 
|  | shared_memory_offset_, 0, testcases[i].fill_mode, | 
|  | testcases[i].mask, | 
|  | GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM, GL_NONE, 0, 0); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(stcfi_cmd)); | 
|  | EXPECT_EQ(testcases[i].expected_error, GetGLError()); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, | 
|  | StencilXFillPathInstancedCHROMIUMFillMode) { | 
|  | SetupExpectationsForApplyingDefaultDirtyState(); | 
|  |  | 
|  | // Test different fill modes. | 
|  | cmds::StencilFillPathInstancedCHROMIUM sfi_cmd; | 
|  | cmds::StencilThenCoverFillPathInstancedCHROMIUM stcfi_cmd; | 
|  |  | 
|  | const GLuint kPaths[] = {client_path_id_, client_path_id_ + 5, | 
|  | client_path_id_, client_path_id_ + 18}; | 
|  | const GLsizei kPathCount = arraysize(kPaths); | 
|  |  | 
|  | static const GLenum kFillModes[] = {GL_INVERT, GL_COUNT_UP_CHROMIUM, | 
|  | GL_COUNT_DOWN_CHROMIUM}; | 
|  | const GLuint kMask = 0x7F; | 
|  |  | 
|  | GLuint* paths = GetSharedMemoryAs<GLuint*>(); | 
|  |  | 
|  | for (size_t i = 0; i < arraysize(kFillModes); ++i) { | 
|  | memcpy(paths, kPaths, sizeof(kPaths)); | 
|  | EXPECT_CALL( | 
|  | *gl_, StencilFillPathInstancedNV(kPathCount, GL_UNSIGNED_INT, paths, 0, | 
|  | kFillModes[i], kMask, GL_NONE, NULL)) | 
|  | .RetiresOnSaturation(); | 
|  | sfi_cmd.Init(kPathCount, GL_UNSIGNED_INT, shared_memory_id_, | 
|  | shared_memory_offset_, 0, kFillModes[i], kMask, GL_NONE, 0, 0); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(sfi_cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | memcpy(paths, kPaths, sizeof(kPaths)); | 
|  | EXPECT_CALL(*gl_, | 
|  | StencilThenCoverFillPathInstancedNV( | 
|  | kPathCount, GL_UNSIGNED_INT, paths, 0, kFillModes[i], kMask, | 
|  | GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV, GL_NONE, NULL)) | 
|  | .RetiresOnSaturation(); | 
|  | stcfi_cmd.Init(kPathCount, GL_UNSIGNED_INT, shared_memory_id_, | 
|  | shared_memory_offset_, 0, kFillModes[i], kMask, | 
|  | GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM, GL_NONE, 0, 0); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(stcfi_cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, InstancedCalls) { | 
|  | SetupExpectationsForApplyingDefaultDirtyState(); | 
|  |  | 
|  | const GLuint kPaths[] = {0, client_path_id_, 15, client_path_id_}; | 
|  | const GLsizei kPathCount = arraysize(kPaths); | 
|  |  | 
|  | // The path base will be client_path_id_, and so 0 is a | 
|  | // valid path. | 
|  | const GLuint kPathBase = client_path_id_; | 
|  | const GLuint kPathsWithBase[] = {0, 5, 0, 18}; | 
|  |  | 
|  | const GLshort kShortPathBase = client_path_id_ * 2; | 
|  | const GLshort kShortPathsWithBase[] = { | 
|  | -static_cast<GLshort>(client_path_id_), 5, | 
|  | -static_cast<GLshort>(client_path_id_), 18}; | 
|  |  | 
|  | const GLenum kFillMode = GL_INVERT; | 
|  | const GLuint kMask = 0x80; | 
|  | const GLuint kReference = 0xFF; | 
|  |  | 
|  | GLfloat transform_values[12 * kPathCount]; | 
|  | for (GLsizei i = 0; i < kPathCount; ++i) { | 
|  | for (int j = 0; j < 12; ++j) { | 
|  | transform_values[i * 12 + j] = 0.1f * j + i; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Path name overflows to correct path. | 
|  | const GLuint kBigPathBase = std::numeric_limits<GLuint>::max(); | 
|  | const GLuint kPathsWithBigBase[] = {client_path_id_ + 1, 5, | 
|  | client_path_id_ + 1, 18}; | 
|  |  | 
|  | // Path name underflows. As a technical limitation, we can not get to correct | 
|  | // path, | 
|  | // so test just tests that there is no GL error. | 
|  | const GLuint kNegativePathBase = 1; | 
|  | const GLbyte kNegativePathsWithBaseByte[] = {-1, -2, -5, -18}; | 
|  | const GLint kNegativePathsWithBaseInt[] = {-2, -3, -4, -5}; | 
|  |  | 
|  | InstancedTestcase testcases[] = { | 
|  | // Test a normal call. | 
|  | {kPathCount, GL_UNSIGNED_INT, kPaths, 0, kFillMode, kReference, kMask, | 
|  | GL_NONE, NULL, sizeof(kPaths), 0, error::kNoError, GL_NO_ERROR, true}, | 
|  | // Test that the path base is applied correctly for each instanced call. | 
|  | {kPathCount, GL_UNSIGNED_INT, kPathsWithBase, kPathBase, kFillMode, | 
|  | kReference, kMask, GL_NONE, NULL, sizeof(kPaths), 0, error::kNoError, | 
|  | GL_NO_ERROR, true}, | 
|  | {kPathCount, GL_UNSIGNED_INT, kPathsWithBase, kPathBase, kFillMode, | 
|  | kReference, kMask, | 
|  |  | 
|  | // Test all possible transform types. The float array is big enough for | 
|  | // all the variants.  The contents of the array in call is not checked, | 
|  | // though. | 
|  | GL_TRANSLATE_X_CHROMIUM, transform_values, sizeof(kPaths), | 
|  | sizeof(transform_values), error::kNoError, GL_NO_ERROR, true}, | 
|  | {kPathCount, GL_UNSIGNED_INT, kPathsWithBase, kPathBase, kFillMode, | 
|  | kReference, kMask, GL_TRANSLATE_Y_CHROMIUM, transform_values, | 
|  | sizeof(kPaths), sizeof(transform_values), error::kNoError, GL_NO_ERROR, | 
|  | true}, | 
|  | {kPathCount, GL_UNSIGNED_INT, kPathsWithBase, kPathBase, kFillMode, | 
|  | kReference, kMask, GL_TRANSLATE_2D_CHROMIUM, transform_values, | 
|  | sizeof(kPaths), sizeof(transform_values), error::kNoError, GL_NO_ERROR, | 
|  | true}, | 
|  | {kPathCount, GL_UNSIGNED_INT, kPathsWithBase, kPathBase, kFillMode, | 
|  | kReference, kMask, GL_TRANSLATE_3D_CHROMIUM, transform_values, | 
|  | sizeof(kPaths), sizeof(transform_values), error::kNoError, GL_NO_ERROR, | 
|  | true}, | 
|  | {kPathCount, GL_UNSIGNED_INT, kPathsWithBase, kPathBase, kFillMode, | 
|  | kReference, kMask, GL_AFFINE_2D_CHROMIUM, transform_values, | 
|  | sizeof(kPaths), sizeof(transform_values), error::kNoError, GL_NO_ERROR, | 
|  | true}, | 
|  | {kPathCount, GL_UNSIGNED_INT, kPathsWithBase, kPathBase, kFillMode, | 
|  | kReference, kMask, GL_AFFINE_3D_CHROMIUM, transform_values, | 
|  | sizeof(kPaths), sizeof(transform_values), error::kNoError, GL_NO_ERROR, | 
|  | true}, | 
|  | {kPathCount, GL_UNSIGNED_INT, kPathsWithBase, kPathBase, kFillMode, | 
|  | kReference, kMask, GL_TRANSPOSE_AFFINE_2D_CHROMIUM, transform_values, | 
|  | sizeof(kPaths), sizeof(transform_values), error::kNoError, GL_NO_ERROR, | 
|  | true}, | 
|  | {kPathCount, GL_UNSIGNED_INT, kPathsWithBase, kPathBase, kFillMode, | 
|  | kReference, kMask, GL_TRANSPOSE_AFFINE_3D_CHROMIUM, transform_values, | 
|  | sizeof(kPaths), sizeof(transform_values), error::kNoError, GL_NO_ERROR, | 
|  | true}, | 
|  | {kPathCount, GL_SHORT, kShortPathsWithBase, kShortPathBase, kFillMode, | 
|  | kReference, kMask, GL_TRANSPOSE_AFFINE_3D_CHROMIUM, transform_values, | 
|  | sizeof(kShortPathsWithBase), sizeof(transform_values), error::kNoError, | 
|  | GL_NO_ERROR, true}, | 
|  |  | 
|  | // Test that if using path base causes path id to overflow, we get no | 
|  | // error. | 
|  | {kPathCount, GL_UNSIGNED_INT, kPathsWithBigBase, kBigPathBase, kFillMode, | 
|  | kReference, kMask, GL_TRANSLATE_X_CHROMIUM, transform_values, | 
|  | sizeof(kPathsWithBigBase), sizeof(transform_values), error::kNoError, | 
|  | GL_NO_ERROR, true}, | 
|  | // Test that if using path base causes path id to underflow, we get no | 
|  | // error. | 
|  | {kPathCount, GL_BYTE, kNegativePathsWithBaseByte, kNegativePathBase, | 
|  | kFillMode, kReference, kMask, GL_TRANSLATE_X_CHROMIUM, transform_values, | 
|  | sizeof(kNegativePathsWithBaseByte), sizeof(transform_values), | 
|  | error::kNoError, GL_NO_ERROR, false}, | 
|  | {kPathCount, GL_INT, kNegativePathsWithBaseInt, kNegativePathBase, | 
|  | kFillMode, kReference, kMask, GL_TRANSLATE_X_CHROMIUM, transform_values, | 
|  | sizeof(kNegativePathsWithBaseInt), sizeof(transform_values), | 
|  | error::kNoError, GL_NO_ERROR, false}, | 
|  |  | 
|  | }; | 
|  |  | 
|  | for (size_t i = 0; i < arraysize(testcases); ++i) { | 
|  | SCOPED_TRACE(testing::Message() << "InstancedCalls testcase " << i); | 
|  | CallAllInstancedCommands(testcases[i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, InstancedNoCalls) { | 
|  | const GLuint kPaths[] = {1, client_path_id_, 5, client_path_id_}; | 
|  | const GLsizei kPathCount = arraysize(kPaths); | 
|  |  | 
|  | const GLenum kFillMode = GL_INVERT; | 
|  | const GLuint kMask = 0x80; | 
|  | const GLuint kReference = 0xFF; | 
|  | GLfloat transform_values[12 * kPathCount]; | 
|  | for (GLsizei i = 0; i < kPathCount; ++i) { | 
|  | for (int j = 0; j < 12; ++j) { | 
|  | transform_values[i * 12 + j] = 0.1f * j + i; | 
|  | } | 
|  | } | 
|  |  | 
|  | // The path base will be client_path_id_, and so 0 is a valid path and others | 
|  | // should be invalid. | 
|  | const GLuint kInvalidPathBase = client_path_id_; | 
|  | const GLuint kInvalidPathsWithBase[] = {1, client_path_id_, 5, 18}; | 
|  |  | 
|  | InstancedTestcase testcases[] = { | 
|  | // Zero path count produces no error, no call. | 
|  | {0, GL_UNSIGNED_INT, NULL, 0, kFillMode, kReference, kMask, GL_NONE, NULL, | 
|  | 0, 0, error::kNoError, GL_NO_ERROR, false}, | 
|  |  | 
|  | // Zero path count, even with path data, produces no error, no call. | 
|  | {0, GL_UNSIGNED_INT, kPaths, 0, kFillMode, kReference, kMask, | 
|  | GL_TRANSLATE_X_CHROMIUM, transform_values, sizeof(kPaths), | 
|  | sizeof(transform_values), error::kNoError, GL_NO_ERROR, false}, | 
|  |  | 
|  | // Negative path count produces error. | 
|  | {-1, GL_UNSIGNED_INT, kPaths, 0, kFillMode, kReference, kMask, | 
|  | GL_TRANSLATE_X_CHROMIUM, transform_values, sizeof(kPaths), | 
|  | sizeof(transform_values), error::kNoError, GL_INVALID_VALUE, false}, | 
|  |  | 
|  | // Passing paths count but not having the shm data is a connection error. | 
|  | {kPathCount, GL_UNSIGNED_INT, NULL, 0, kFillMode, kReference, kMask, | 
|  | GL_TRANSLATE_X_CHROMIUM, transform_values, 0, sizeof(transform_values), | 
|  | error::kOutOfBounds, GL_NO_ERROR, false}, | 
|  |  | 
|  | // Huge path count would cause huge transfer buffer, it does not go | 
|  | // through. | 
|  | {std::numeric_limits<GLsizei>::max() - 3, GL_UNSIGNED_INT, kPaths, 0, | 
|  | kFillMode, kReference, kMask, GL_TRANSLATE_X_CHROMIUM, transform_values, | 
|  | sizeof(kPaths), sizeof(transform_values), error::kOutOfBounds, | 
|  | GL_NO_ERROR, false}, | 
|  |  | 
|  | // Test that the path base is applied correctly for each instanced call. | 
|  | // In this case no path is marked as used, and so no GL function should be | 
|  | // called and no error should be generated. | 
|  | {kPathCount, GL_UNSIGNED_INT, kInvalidPathsWithBase, kInvalidPathBase, | 
|  | kFillMode, kReference, kMask, GL_TRANSLATE_X_CHROMIUM, transform_values, | 
|  | sizeof(kInvalidPathsWithBase), sizeof(transform_values), error::kNoError, | 
|  | GL_NO_ERROR, false}, | 
|  |  | 
|  | // Test that using correct paths but invalid transform type produces | 
|  | // invalid enum. | 
|  | {kPathCount, GL_UNSIGNED_INT, kPaths, 0, kFillMode, kReference, kMask, | 
|  | GL_TRANSLATE_X_CHROMIUM - 1, transform_values, sizeof(kPaths), | 
|  | sizeof(transform_values), error::kNoError, GL_INVALID_ENUM, false}, | 
|  |  | 
|  | // Test that if we have transform, not having the shm data is a connection | 
|  | // error. | 
|  | {kPathCount, GL_UNSIGNED_INT, kPaths, 0, kFillMode, kReference, kMask, | 
|  | GL_TRANSLATE_X_CHROMIUM, NULL, sizeof(kPaths), 0, error::kOutOfBounds, | 
|  | GL_NO_ERROR, false}, | 
|  |  | 
|  | }; | 
|  | for (size_t i = 0; i < arraysize(testcases); ++i) { | 
|  | SCOPED_TRACE(testing::Message() << "InstancedNoCalls testcase " << i); | 
|  | CallAllInstancedCommands(testcases[i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, InstancedInvalidSHMValues) { | 
|  | const GLuint kPaths[] = {1, client_path_id_, 5, client_path_id_}; | 
|  | const GLsizei kPathCount = arraysize(kPaths); | 
|  | GLfloat transform_values[12 * kPathCount]; | 
|  | for (GLsizei i = 0; i < kPathCount; ++i) { | 
|  | for (int j = 0; j < 12; ++j) { | 
|  | transform_values[i * 12 + j] = 0.1f * j + i; | 
|  | } | 
|  | } | 
|  | enum { | 
|  | kPathsSHMIdInvalid = 1, | 
|  | kPathsSHMOffsetInvalid = 1 << 1, | 
|  | kTransformsHMIdInvalid = 1 << 2, | 
|  | kTransformsHMOffsetInvalid = 1 << 3, | 
|  | kFirstTestcase = kPathsSHMIdInvalid, | 
|  | kLastTestcase = kTransformsHMOffsetInvalid | 
|  | }; | 
|  |  | 
|  | for (int testcase = kFirstTestcase; testcase <= kLastTestcase; ++testcase) { | 
|  | GLfloat* transforms = GetSharedMemoryAs<GLfloat*>(); | 
|  | uint32 transforms_shm_id = shared_memory_id_; | 
|  | uint32 transforms_shm_offset = shared_memory_offset_; | 
|  | memcpy(transforms, transform_values, sizeof(transform_values)); | 
|  |  | 
|  | GLuint* paths = | 
|  | GetSharedMemoryAsWithOffset<GLuint*>(sizeof(transform_values)); | 
|  | uint32 paths_shm_id = shared_memory_id_; | 
|  | uint32 paths_shm_offset = shared_memory_offset_ + sizeof(transform_values); | 
|  |  | 
|  | if (testcase & kPathsSHMIdInvalid) { | 
|  | paths_shm_id = kInvalidSharedMemoryId; | 
|  | } | 
|  | if (testcase & kPathsSHMOffsetInvalid) { | 
|  | paths_shm_offset = kInvalidSharedMemoryOffset; | 
|  | } | 
|  | if (testcase & kTransformsHMIdInvalid) { | 
|  | transforms_shm_id = kInvalidSharedMemoryId; | 
|  | } | 
|  | if (testcase & kTransformsHMOffsetInvalid) { | 
|  | transforms_shm_offset = kInvalidSharedMemoryOffset; | 
|  | } | 
|  | SCOPED_TRACE(testing::Message() << "InstancedInvalidSHMValues testcase " | 
|  | << testcase); | 
|  | CallAllInstancedCommandsWithInvalidSHM( | 
|  | kPathCount, kPaths, paths, paths_shm_id, paths_shm_offset, | 
|  | transforms_shm_id, transforms_shm_offset); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, | 
|  | BindFragmentInputLocationCHROMIUM) { | 
|  | const uint32 kBucketId = 123; | 
|  | const GLint kLocation = 2; | 
|  | const char* kName = "testing"; | 
|  | const char* kBadName1 = "gl_testing"; | 
|  |  | 
|  | SetBucketAsCString(kBucketId, kName); | 
|  | cmds::BindFragmentInputLocationCHROMIUMBucket cmd; | 
|  | cmd.Init(client_program_id_, kLocation, kBucketId); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | // Check negative location. | 
|  | SetBucketAsCString(kBucketId, kName); | 
|  | cmd.Init(client_program_id_, -1, kBucketId); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  | // Check the highest location. | 
|  | SetBucketAsCString(kBucketId, kName); | 
|  | const GLint kMaxLocation = kMaxVaryingVectors * 4 - 1; | 
|  | cmd.Init(client_program_id_, kMaxLocation, kBucketId); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | // Check too high location. | 
|  | SetBucketAsCString(kBucketId, kName); | 
|  | cmd.Init(client_program_id_, kMaxLocation + 1, kBucketId); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  | // Check bad name "gl_...". | 
|  | SetBucketAsCString(kBucketId, kBadName1); | 
|  | cmd.Init(client_program_id_, kLocation, kBucketId); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); | 
|  | } | 
|  |  | 
|  | #include "gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions_autogen.h" | 
|  |  | 
|  | }  // namespace gles2 | 
|  | }  // namespace gpu |