| // Copyright 2018 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/vr/graphics_delegate_win.h" |
| |
| #include "components/viz/common/resources/shared_image_format_utils.h" |
| #include "content/public/browser/gpu_utils.h" |
| #include "content/public/common/gpu_stream_constants.h" |
| #include "device/vr/public/mojom/vr_service.mojom.h" |
| #include "gpu/command_buffer/client/client_shared_image.h" |
| #include "gpu/command_buffer/client/gles2_interface.h" |
| #include "gpu/command_buffer/client/gles2_lib.h" |
| #include "gpu/command_buffer/client/shared_image_interface.h" |
| #include "gpu/command_buffer/common/context_creation_attribs.h" |
| #include "gpu/command_buffer/common/shared_image_usage.h" |
| #include "mojo/public/cpp/bindings/sync_call_restrictions.h" |
| |
| namespace vr { |
| |
| GraphicsDelegateWin::GraphicsDelegateWin() = default; |
| GraphicsDelegateWin::~GraphicsDelegateWin() = default; |
| |
| void GraphicsDelegateWin::Initialize(base::OnceClosure on_initialized) { |
| gpu::GpuChannelEstablishFactory* factory = |
| content::GetGpuChannelEstablishFactory(); |
| gpu_channel_host_ = factory->EstablishGpuChannelSync(); |
| |
| context_provider_ = viz::ContextProviderCommandBuffer::CreateForGL( |
| gpu_channel_host_, content::kGpuStreamIdDefault, |
| content::kGpuStreamPriorityUI, GURL(std::string("chrome://gpu/VrUiWin")), |
| viz::command_buffer_metrics::ContextType::XR_COMPOSITING); |
| |
| if (context_provider_->BindToCurrentSequence() == |
| gpu::ContextResult::kSuccess) { |
| gl_ = context_provider_->ContextGL(); |
| sii_ = context_provider_->SharedImageInterface(); |
| } |
| |
| std::move(on_initialized).Run(); |
| } |
| |
| bool GraphicsDelegateWin::BindContext() { |
| if (!gl_) |
| return false; |
| |
| gles2::SetGLContext(gl_); |
| return true; |
| } |
| |
| void GraphicsDelegateWin::ClearContext() { |
| gles2::SetGLContext(nullptr); |
| } |
| |
| bool GraphicsDelegateWin::PreRender() { |
| if (!gl_) |
| return false; |
| |
| BindContext(); |
| |
| // Create a memory buffer and a shared image referencing that memory buffer. |
| if (!EnsureMemoryBuffer()) { |
| return false; |
| } |
| |
| // Create a texture id and associate it with shared image. |
| shared_image_texture_ = client_shared_image_->CreateGLTexture(gl_); |
| scoped_shared_image_access_ = |
| shared_image_texture_->BeginAccess(gpu::SyncToken(), /*readonly=*/false); |
| |
| gl_->BindTexture(GL_TEXTURE_2D, scoped_shared_image_access_->texture_id()); |
| gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| gl_->BindTexture(GL_TEXTURE_2D, 0); |
| |
| // Bind our image/texture/memory buffer as the draw framebuffer. |
| gl_->GenFramebuffers(1, &draw_frame_buffer_); |
| gl_->BindFramebuffer(GL_DRAW_FRAMEBUFFER, draw_frame_buffer_); |
| gl_->FramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, |
| scoped_shared_image_access_->texture_id(), 0); |
| |
| if (gl_->GetError() != GL_NO_ERROR) { |
| gpu::SharedImageTexture::ScopedAccess::EndAccess( |
| std::move(scoped_shared_image_access_)); |
| shared_image_texture_.reset(); |
| // Clear any remaining GL errors. |
| while (gl_->GetError() != GL_NO_ERROR) { |
| } |
| return false; |
| } |
| |
| return true; |
| } |
| |
| void GraphicsDelegateWin::PostRender() { |
| // Unbind the drawing buffer. |
| gl_->BindFramebuffer(GL_FRAMEBUFFER, 0); |
| gl_->DeleteFramebuffers(1, &draw_frame_buffer_); |
| |
| // Generate a SyncToken after GPU is done accessing the texture. |
| access_done_sync_token_ = gpu::SharedImageTexture::ScopedAccess::EndAccess( |
| std::move(scoped_shared_image_access_)); |
| sii_->VerifySyncToken(access_done_sync_token_); |
| shared_image_texture_.reset(); |
| gl_->BindTexture(GL_TEXTURE_2D, 0); |
| draw_frame_buffer_ = 0; |
| |
| // Flush. |
| gl_->ShallowFlushCHROMIUM(); |
| ClearContext(); |
| } |
| |
| gfx::GpuMemoryBufferHandle GraphicsDelegateWin::GetTexture() { |
| if (!client_shared_image_) { |
| return gfx::GpuMemoryBufferHandle(); |
| } |
| |
| return client_shared_image_->CloneGpuMemoryBufferHandle(); |
| } |
| |
| gpu::SyncToken GraphicsDelegateWin::GetSyncToken() { |
| return access_done_sync_token_; |
| } |
| |
| bool GraphicsDelegateWin::EnsureMemoryBuffer() { |
| gfx::Size buffer_size = GetTextureSize(); |
| if (client_shared_image_ && last_size_ == buffer_size) { |
| return true; |
| } |
| |
| // Destroy any existing SharedImage as its size is not correct. |
| ResetMemoryBuffer(); |
| |
| last_size_ = buffer_size; |
| |
| viz::SharedImageFormat format = viz::SinglePlaneFormat::kRGBA_8888; |
| |
| // These SharedImages will be written to via GLES2 to render the scene, |
| // followed by having their underlying GMBHandle sent off to be displayed in |
| // an overlay. |
| client_shared_image_ = sii_->CreateSharedImage( |
| {format, buffer_size, gfx::ColorSpace(), |
| gpu::SHARED_IMAGE_USAGE_GLES2_WRITE, "VRGraphicsDelegate"}, |
| gpu::kNullSurfaceHandle, gfx::BufferUsage::SCANOUT); |
| if (!client_shared_image_) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| void GraphicsDelegateWin::ResetMemoryBuffer() { |
| if (client_shared_image_) { |
| sii_->DestroySharedImage(access_done_sync_token_, |
| std::move(client_shared_image_)); |
| } |
| access_done_sync_token_.Clear(); |
| } |
| |
| void GraphicsDelegateWin::ClearBufferToBlack() { |
| gl_->ClearColor(0, 0, 0, 0); |
| gl_->Clear(GL_COLOR_BUFFER_BIT); |
| } |
| |
| } // namespace vr |