| // Copyright 2020 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 "ui/gl/gl_fence_win.h" |
| |
| #include "base/logging.h" |
| #include "base/notreached.h" |
| #include "ui/gl/gl_angle_util_win.h" |
| |
| #include <d3d11_4.h> |
| |
| namespace gl { |
| |
| bool GLFenceWin::IsSupported() { |
| Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device = |
| gl::QueryD3D11DeviceObjectFromANGLE(); |
| if (!d3d11_device) |
| return false; |
| |
| // Support for ID3D11Device5 implies support for ID3D11DeviceContext4. |
| // No point in letting you create fences if you can't signal or wait on them. |
| Microsoft::WRL::ComPtr<ID3D11Device5> d3d11_device5; |
| HRESULT hr = d3d11_device.As(&d3d11_device5); |
| if (FAILED(hr)) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| std::unique_ptr<GLFenceWin> GLFenceWin::CreateForGpuFence() { |
| Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device = |
| gl::QueryD3D11DeviceObjectFromANGLE(); |
| if (!d3d11_device) { |
| DLOG(ERROR) << "Unable to retrieve ID3D11Device from ANGLE"; |
| return nullptr; |
| } |
| |
| return CreateForGpuFence(d3d11_device.Get()); |
| } |
| |
| std::unique_ptr<GLFenceWin> GLFenceWin::CreateForGpuFence( |
| ID3D11Device* d3d11_device) { |
| Microsoft::WRL::ComPtr<ID3D11Device5> d3d11_device5; |
| HRESULT hr = d3d11_device->QueryInterface(IID_PPV_ARGS(&d3d11_device5)); |
| if (FAILED(hr)) { |
| DLOG(ERROR) << "Unable to retrieve ID3D11Device5 interface " |
| << logging::SystemErrorCodeToString(hr); |
| return nullptr; |
| } |
| |
| Microsoft::WRL::ComPtr<ID3D11Fence> d3d11_fence; |
| hr = d3d11_device5->CreateFence(0, D3D11_FENCE_FLAG_SHARED, |
| IID_PPV_ARGS(&d3d11_fence)); |
| if (FAILED(hr)) { |
| DLOG(ERROR) << "Unable to create ID3D11Fence " |
| << logging::SystemErrorCodeToString(hr); |
| return nullptr; |
| } |
| |
| HANDLE shared_handle; |
| hr = d3d11_fence->CreateSharedHandle( |
| nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr, |
| &shared_handle); |
| if (FAILED(hr)) { |
| DLOG(ERROR) << "Unable to create shared handle for DXGIResource " |
| << logging::SystemErrorCodeToString(hr); |
| return nullptr; |
| } |
| |
| // Put the shared handle into an RAII object as quickly as possible to |
| // ensure we do not leak it. |
| base::win::ScopedHandle scoped_handle(shared_handle); |
| |
| Microsoft::WRL::ComPtr<ID3D11DeviceContext> d3d11_device_context; |
| d3d11_device5->GetImmediateContext(&d3d11_device_context); |
| |
| Microsoft::WRL::ComPtr<ID3D11DeviceContext4> d3d11_device_context4; |
| hr = d3d11_device_context.As(&d3d11_device_context4); |
| if (FAILED(hr)) { |
| DLOG(ERROR) << "Unable to retrieve ID3D11DeviceContext4 interface " |
| << logging::SystemErrorCodeToString(hr); |
| return nullptr; |
| } |
| |
| hr = d3d11_device_context4->Signal(d3d11_fence.Get(), 1); |
| if (FAILED(hr)) { |
| DLOG(ERROR) << "Unable to Signal D3D11 fence " |
| << logging::SystemErrorCodeToString(hr); |
| return nullptr; |
| } |
| |
| gfx::GpuFenceHandle gpu_fence_handle; |
| gpu_fence_handle.owned_handle = std::move(scoped_handle); |
| return std::make_unique<GLFenceWin>(std::move(d3d11_fence), |
| std::move(gpu_fence_handle)); |
| } |
| |
| std::unique_ptr<GLFenceWin> GLFenceWin::CreateFromGpuFence( |
| const gfx::GpuFence& gpu_fence) { |
| Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device = |
| gl::QueryD3D11DeviceObjectFromANGLE(); |
| return CreateFromGpuFence(d3d11_device.Get(), gpu_fence); |
| } |
| |
| std::unique_ptr<GLFenceWin> GLFenceWin::CreateFromGpuFence( |
| ID3D11Device* d3d11_device, |
| const gfx::GpuFence& gpu_fence) { |
| Microsoft::WRL::ComPtr<ID3D11Device5> d3d11_device5; |
| HRESULT hr = d3d11_device->QueryInterface(IID_PPV_ARGS(&d3d11_device5)); |
| if (FAILED(hr)) { |
| DLOG(ERROR) << "Unable to retrieve ID3D11Device5 interface " |
| << logging::SystemErrorCodeToString(hr); |
| return nullptr; |
| } |
| |
| gfx::GpuFenceHandle gpu_fence_handle = gpu_fence.GetGpuFenceHandle().Clone(); |
| Microsoft::WRL::ComPtr<ID3D11Fence> d3d11_fence; |
| hr = d3d11_device5->OpenSharedFence(gpu_fence_handle.owned_handle.Get(), |
| IID_PPV_ARGS(&d3d11_fence)); |
| if (FAILED(hr)) { |
| DLOG(ERROR) << "Unable to open a shared fence " |
| << logging::SystemErrorCodeToString(hr); |
| return nullptr; |
| } |
| |
| return std::make_unique<GLFenceWin>(std::move(d3d11_fence), |
| std::move(gpu_fence_handle)); |
| } |
| |
| GLFenceWin::GLFenceWin(Microsoft::WRL::ComPtr<ID3D11Fence> d3d11_fence, |
| gfx::GpuFenceHandle gpu_fence_handle) |
| : d3d11_fence_(std::move(d3d11_fence)), |
| gpu_fence_handle_(std::move(gpu_fence_handle)) {} |
| |
| GLFenceWin::~GLFenceWin() = default; |
| |
| bool GLFenceWin::HasCompleted() { |
| NOTREACHED(); |
| return false; |
| } |
| |
| void GLFenceWin::ClientWait() { |
| NOTREACHED(); |
| } |
| |
| void GLFenceWin::ServerWait() { |
| Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device; |
| d3d11_fence_->GetDevice(&d3d11_device); |
| |
| Microsoft::WRL::ComPtr<ID3D11DeviceContext> d3d11_device_context; |
| d3d11_device->GetImmediateContext(&d3d11_device_context); |
| |
| Microsoft::WRL::ComPtr<ID3D11DeviceContext4> d3d11_device_context4; |
| HRESULT hr = d3d11_device_context.As(&d3d11_device_context4); |
| if (FAILED(hr)) { |
| DLOG(ERROR) << "Unable to retrieve ID3D11DeviceContext4 interface " |
| << logging::SystemErrorCodeToString(hr); |
| return; |
| } |
| |
| hr = d3d11_device_context4->Wait(d3d11_fence_.Get(), 1); |
| if (FAILED(hr)) { |
| DLOG(ERROR) << "Unable to Wait on D3D11 fence " |
| << logging::SystemErrorCodeToString(hr); |
| return; |
| } |
| } |
| |
| std::unique_ptr<gfx::GpuFence> GLFenceWin::GetGpuFence() { |
| return std::make_unique<gfx::GpuFence>(gpu_fence_handle_.Clone()); |
| } |
| |
| } // namespace gl |