diff --git a/gpu/command_buffer/service/shared_image/egl_image_backing.cc b/gpu/command_buffer/service/shared_image/egl_image_backing.cc index d04887c446b6e..8567b76171464 100644 --- a/gpu/command_buffer/service/shared_image/egl_image_backing.cc +++ b/gpu/command_buffer/service/shared_image/egl_image_backing.cc @@ -471,6 +471,12 @@ EGLImageBacking::GenEGLImageSiblings(base::span pixel_data) { AutoLock auto_lock(this); create_egl_images = egl_images_.empty(); if (create_egl_images) { + if (!pixel_data.empty()) { + // Drain any pre-existing GL errors so we can attribute failures to the + // allocation/upload below before deciding whether to SetCleared(). + while (api->glGetErrorFn() != GL_NO_ERROR) { + } + } for (int plane = 0; plane < num_planes; plane++) { gl::ScopedEGLImage egl_image = GenEGLImageSibling(pixel_data, service_ids, plane); @@ -527,7 +533,19 @@ EGLImageBacking::GenEGLImageSiblings(base::span pixel_data) { // SetCleared() acquires the lock. Hence it is kept outside of previous lock // above. if (!pixel_data.empty()) { - SetCleared(); + // glTexStorage2D in GenEGLImageSibling() allocates undefined-content + // storage on a context without robust-resource-init. If the following + // glTexSubImage2D failed (e.g. GL_OUT_OF_MEMORY) the storage is still + // uninitialised; do not defeat the IsCleared() gate in that case. + GLenum error = api->glGetErrorFn(); + if (error == GL_NO_ERROR) { + SetCleared(); + } else { + LOG(ERROR) << "EGLImageBacking: initial pixel upload failed (GL error 0x" + << std::hex << error + << "); backing will remain uncleared to avoid exposing " + "uninitialised GPU memory"; + } } std::vector> texture_holders; diff --git a/gpu/command_buffer/service/shared_image/gl_texture_image_backing.cc b/gpu/command_buffer/service/shared_image/gl_texture_image_backing.cc index c3f178bc8a454..993a50a0cf649 100644 --- a/gpu/command_buffer/service/shared_image/gl_texture_image_backing.cc +++ b/gpu/command_buffer/service/shared_image/gl_texture_image_backing.cc @@ -501,6 +501,11 @@ void GLTextureImageBacking::InitializeGLTexture( "GLSharedImage_" + SharedImageBacking::debug_label(); int num_planes = format().NumberOfPlanes(); textures_.reserve(num_planes); + // Drain any pre-existing GL errors so we can attribute failures to the + // allocation/upload below. + gl::GLApi* api = gl::g_current_gl_context; + while (api->glGetErrorFn() != GL_NO_ERROR) { + } for (int plane = 0; plane < num_planes; ++plane) { auto plane_format = GLTextureHolder::GetPlaneFormat(format(), plane); textures_.emplace_back(plane_format, format().GetPlaneSize(plane, size()), @@ -511,7 +516,23 @@ void GLTextureImageBacking::InitializeGLTexture( } if (!pixel_data.empty()) { - SetCleared(); + // glTexStorage2D allocates undefined-content storage on the + // SharedContextState GL context (robust-resource-init is disabled in + // production). The subsequent glTexSubImage2D may fail (e.g. + // GL_OUT_OF_MEMORY on the staging upload) leaving the storage + // uninitialised. Only mark the backing cleared if no GL error was raised, + // so the IsCleared() gate on read access continues to protect + // uninitialised GPU memory. + GLenum error = api->glGetErrorFn(); + if (error == GL_NO_ERROR) { + SetCleared(); + } else { + LOG(ERROR) << "GLTextureImageBacking: initial pixel upload failed (GL " + "error 0x" + << std::hex << error + << "); backing will remain uncleared to avoid exposing " + "uninitialised GPU memory"; + } } }