WebGPU support for Windows OpenXR WebXR
This change enables WebGPU XRSessions on the Windows OpenXR backend by enabling SharedBuffer support. Bug: 359418629 Change-Id: Ia9c6784cf0fd836eaf4a078dcafb94aaa77992e0 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5942102 Reviewed-by: Alexander Cooper <alcooper@chromium.org> Commit-Queue: Brandon Jones <bajones@chromium.org> Cr-Commit-Position: refs/heads/main@{#1378648}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
630cdd2a95
commit
a1549c0d70
@ -85,8 +85,8 @@ void OpenXrGraphicsBinding::PrepareViewConfigForRender(
|
||||
// steps.
|
||||
if (ShouldFlipSubmittedImage()) {
|
||||
projection_view.subImage.imageRect.offset.y = 0;
|
||||
projection_view.fov.angleUp = view.fov.angleDown;
|
||||
projection_view.fov.angleDown = view.fov.angleUp;
|
||||
projection_view.fov.angleUp = -view.fov.angleUp;
|
||||
projection_view.fov.angleDown = -view.fov.angleDown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,6 +68,11 @@ struct SwapChainInfo {
|
||||
// When shared images are being used, there is a corresponding MailboxHolder
|
||||
// and D3D11Fence for each D3D11 texture in the vector.
|
||||
raw_ptr<ID3D11Texture2D> d3d11_texture = nullptr;
|
||||
// If a shared handle cannot be created for the swap chain texture, a second
|
||||
// texture which is shareable will be created and passed to the renderer
|
||||
// proceess. When the frame is complete it will be copied to the swap chain
|
||||
// texture prior to submission.
|
||||
Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d11_shared_texture = nullptr;
|
||||
Microsoft::WRL::ComPtr<ID3D11Fence> d3d11_fence;
|
||||
#elif BUILDFLAG(IS_ANDROID)
|
||||
// Ideally this would be a gluint, but there are conflicting headers for GL
|
||||
@ -233,7 +238,7 @@ class OpenXrGraphicsBinding {
|
||||
// Called to indicate which graphics API produced the textures submitted to
|
||||
// OpenXR. Does not affect the API used for compositing.
|
||||
void SetWebGPUSession(bool is_webgpu) { webgpu_session_ = is_webgpu; }
|
||||
bool IsWebGPUSession() { return webgpu_session_; }
|
||||
bool IsWebGPUSession() const { return webgpu_session_; }
|
||||
|
||||
protected:
|
||||
// Internal helper to clear the list of images allocated during
|
||||
|
@ -85,7 +85,7 @@ int64_t OpenXrGraphicsBindingD3D11::GetSwapchainFormat(
|
||||
// OpenXR's swapchain format expects to describe the texture content.
|
||||
// The result of a swapchain image created from OpenXR API always contains a
|
||||
// typeless texture. On the other hand, WebGL API uses CSS color convention
|
||||
// that's sRGB. The RGBA typelss texture from OpenXR swapchain image leads to
|
||||
// that's sRGB. The RGBA typeless texture from OpenXR swapchain image leads to
|
||||
// a linear format render target view (reference to function
|
||||
// D3D11TextureHelper::EnsureRenderTargetView in d3d11_texture_helper.cc).
|
||||
// Therefore, the content in this openxr swapchain image is in sRGB format.
|
||||
@ -127,7 +127,7 @@ base::span<SwapChainInfo> OpenXrGraphicsBindingD3D11::GetSwapChainImages() {
|
||||
bool OpenXrGraphicsBindingD3D11::CanUseSharedImages() const {
|
||||
// Put shared image feature behind a flag until remaining issues with overlays
|
||||
// are resolved.
|
||||
return !base::FeatureList::IsEnabled(device::features::kOpenXRSharedImages);
|
||||
return base::FeatureList::IsEnabled(device::features::kOpenXRSharedImages);
|
||||
}
|
||||
|
||||
void OpenXrGraphicsBindingD3D11::CreateSharedImages(
|
||||
@ -162,10 +162,53 @@ void OpenXrGraphicsBindingD3D11::CreateSharedImages(
|
||||
hr = dxgi_resource->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 "
|
||||
<< std::hex << hr;
|
||||
return;
|
||||
DLOG(ERROR) << "Unable to create shared handle for DXGIResource (0x"
|
||||
<< std::hex << hr << "). Creating a separate shareable "
|
||||
<< "texture instead.";
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
desc.Width = texture2d_desc.Width;
|
||||
desc.Height = texture2d_desc.Height;
|
||||
desc.MipLevels = 1;
|
||||
desc.ArraySize = 1;
|
||||
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.SampleDesc.Quality = 0;
|
||||
desc.Usage = D3D11_USAGE_DEFAULT;
|
||||
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
|
||||
desc.CPUAccessFlags = 0;
|
||||
desc.MiscFlags =
|
||||
D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED;
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
|
||||
texture_helper_->GetDevice();
|
||||
hr = d3d11_device->CreateTexture2D(&desc, nullptr,
|
||||
&swap_chain_info.d3d11_shared_texture);
|
||||
if (FAILED(hr)) {
|
||||
DLOG(ERROR) << "Failed to create shared texture (0x" << std::hex << hr
|
||||
<< ")";
|
||||
return;
|
||||
}
|
||||
|
||||
hr = swap_chain_info.d3d11_shared_texture->QueryInterface(
|
||||
IID_PPV_ARGS(&dxgi_resource));
|
||||
if (FAILED(hr)) {
|
||||
DLOG(ERROR) << "QueryInterface for IDXGIResource of shared texture "
|
||||
"failed with error 0x"
|
||||
<< std::hex << hr;
|
||||
return;
|
||||
}
|
||||
|
||||
hr = dxgi_resource->CreateSharedHandle(
|
||||
nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE,
|
||||
nullptr, &shared_handle);
|
||||
if (FAILED(hr)) {
|
||||
DLOG(ERROR)
|
||||
<< "Unable to create shared handle for fallback DXGIResource (0x"
|
||||
<< std::hex << hr << ").";
|
||||
}
|
||||
}
|
||||
|
||||
gfx::GpuMemoryBufferHandle gpu_memory_buffer_handle;
|
||||
@ -182,13 +225,18 @@ void OpenXrGraphicsBindingD3D11::CreateSharedImages(
|
||||
gfx::Size(texture2d_desc.Width, texture2d_desc.Height);
|
||||
|
||||
// The SharedImages created here will eventually be transferred to other
|
||||
// processes to have their contents written by WebGL and read via GL by
|
||||
// OpenXR.
|
||||
const gpu::SharedImageUsageSet shared_image_usage =
|
||||
// processes to have their contents written by WebGL or WebGPU.
|
||||
// Readback by OpenXR is always via OpenGL.
|
||||
gpu::SharedImageUsageSet shared_image_usage =
|
||||
gpu::SHARED_IMAGE_USAGE_SCANOUT | gpu::SHARED_IMAGE_USAGE_DISPLAY_READ |
|
||||
gpu::SHARED_IMAGE_USAGE_GLES2_READ |
|
||||
gpu::SHARED_IMAGE_USAGE_GLES2_WRITE;
|
||||
|
||||
if (IsWebGPUSession()) {
|
||||
shared_image_usage |= gpu::SHARED_IMAGE_USAGE_WEBGPU_READ |
|
||||
gpu::SHARED_IMAGE_USAGE_WEBGPU_WRITE;
|
||||
}
|
||||
|
||||
swap_chain_info.shared_image = sii->CreateSharedImage(
|
||||
{viz::SinglePlaneFormat::kRGBA_8888, buffer_size,
|
||||
gfx::ColorSpace(gfx::ColorSpace::PrimaryID::BT709,
|
||||
@ -265,6 +313,19 @@ bool OpenXrGraphicsBindingD3D11::WaitOnFence(gfx::GpuFence& gpu_fence) {
|
||||
|
||||
bool OpenXrGraphicsBindingD3D11::Render(
|
||||
const scoped_refptr<viz::ContextProvider>& context_provider) {
|
||||
const SwapChainInfo& swap_chain_image = GetActiveSwapchainImage();
|
||||
if (swap_chain_image.d3d11_shared_texture) {
|
||||
// If a separate shared texture is being used, copy it into the original
|
||||
// swap chain texture prior to any further compositing. The shared texture
|
||||
// should always be the same size and format as the swap chain texture, so
|
||||
// a direct copy can be done rather than a render pass.
|
||||
texture_helper_->GetDeviceContext()->CopyResource(
|
||||
/*destination=*/swap_chain_image.d3d11_texture.get(),
|
||||
/*source=*/swap_chain_image.d3d11_shared_texture.Get());
|
||||
}
|
||||
|
||||
// Even if a shared image was copied, always perform a composite to account
|
||||
// for any necessary overlays.
|
||||
return texture_helper_->UpdateBackbufferSizes() &&
|
||||
texture_helper_->CompositeToBackBuffer(context_provider);
|
||||
}
|
||||
@ -274,7 +335,7 @@ void OpenXrGraphicsBindingD3D11::CleanupWithoutSubmit() {
|
||||
}
|
||||
|
||||
bool OpenXrGraphicsBindingD3D11::ShouldFlipSubmittedImage() {
|
||||
return IsUsingSharedImages();
|
||||
return IsUsingSharedImages() && !IsWebGPUSession();
|
||||
}
|
||||
|
||||
void OpenXrGraphicsBindingD3D11::OnSwapchainImageSizeChanged() {
|
||||
@ -287,7 +348,8 @@ void OpenXrGraphicsBindingD3D11::OnSwapchainImageActivated(
|
||||
CHECK(active_swapchain_index() < color_swapchain_images_.size());
|
||||
|
||||
texture_helper_->SetBackbuffer(
|
||||
color_swapchain_images_[active_swapchain_index()].d3d11_texture.get());
|
||||
color_swapchain_images_[active_swapchain_index()].d3d11_texture.get(),
|
||||
IsUsingSharedImages(), ShouldFlipSubmittedImage());
|
||||
}
|
||||
|
||||
void OpenXrGraphicsBindingD3D11::SetOverlayAndWebXrVisibility(
|
||||
@ -304,6 +366,7 @@ void OpenXrGraphicsBindingD3D11::SetWebXrTexture(
|
||||
base::win::ScopedHandle scoped_handle = texture_handle.is_valid()
|
||||
? texture_handle.TakeHandle()
|
||||
: base::win::ScopedHandle();
|
||||
|
||||
texture_helper_->SetSourceTexture(std::move(scoped_handle), sync_token, left,
|
||||
right);
|
||||
}
|
||||
|
@ -189,9 +189,10 @@ bool D3D11TextureHelper::CompositeToBackBuffer(
|
||||
|
||||
// Source texture is optional depending on whether we're using
|
||||
// shared images for the destination.
|
||||
if (!render_state_.source_.source_texture_ &&
|
||||
!render_state_.overlay_.source_texture_)
|
||||
if ((backbuffer_contains_source_ || !render_state_.source_.source_texture_) &&
|
||||
!render_state_.overlay_.source_texture_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
gpu::gles2::GLES2Interface* gl = context_provider->ContextGL();
|
||||
if (!gl) {
|
||||
@ -252,7 +253,9 @@ bool D3D11TextureHelper::CompositeToBackBuffer(
|
||||
}
|
||||
|
||||
if (render_state_.overlay_.source_texture_ &&
|
||||
(!render_state_.source_.source_texture_ || !source_visible_)) {
|
||||
((!backbuffer_contains_source_ &&
|
||||
!render_state_.source_.source_texture_) ||
|
||||
!source_visible_)) {
|
||||
// If we have an overlay, but no WebXR texture under it, clear the target
|
||||
// first, since overlay may assume transparency.
|
||||
float color_rgba[4] = {0, 0, 0, 1};
|
||||
@ -410,51 +413,59 @@ bool D3D11TextureHelper::BindTarget() {
|
||||
void PushVertRect(std::vector<Vertex2D>& data,
|
||||
const gfx::RectF& rect,
|
||||
const gfx::RectF& uv,
|
||||
int target) {
|
||||
int target,
|
||||
bool y_flip) {
|
||||
Vertex2D vert;
|
||||
vert.target = target;
|
||||
|
||||
// If the texture is being flipped, the top and bottom Y UV coordinates need
|
||||
// to be swapped.
|
||||
float y_top = y_flip ? uv.y() + uv.height() : uv.y();
|
||||
float y_bottom = y_flip ? uv.y() : uv.y() + uv.height();
|
||||
|
||||
vert.x = rect.x() * 2 - 1;
|
||||
vert.y = rect.y() * 2 - 1;
|
||||
vert.u = uv.x();
|
||||
vert.v = uv.y();
|
||||
vert.v = y_top;
|
||||
data.push_back(vert);
|
||||
|
||||
vert.x = rect.x() * 2 - 1;
|
||||
vert.y = (rect.y() + rect.height()) * 2 - 1;
|
||||
vert.u = uv.x();
|
||||
vert.v = uv.y() + uv.height();
|
||||
vert.v = y_bottom;
|
||||
data.push_back(vert);
|
||||
|
||||
vert.x = (rect.x() + rect.width()) * 2 - 1;
|
||||
vert.y = (rect.y() + rect.height()) * 2 - 1;
|
||||
vert.u = uv.x() + uv.width();
|
||||
vert.v = uv.y() + uv.height();
|
||||
vert.v = y_bottom;
|
||||
data.push_back(vert);
|
||||
|
||||
vert.x = rect.x() * 2 - 1;
|
||||
vert.y = rect.y() * 2 - 1;
|
||||
vert.u = uv.x();
|
||||
vert.v = uv.y();
|
||||
vert.v = y_top;
|
||||
data.push_back(vert);
|
||||
|
||||
vert.x = (rect.x() + rect.width()) * 2 - 1;
|
||||
vert.y = (rect.y() + rect.height()) * 2 - 1;
|
||||
vert.u = uv.x() + uv.width();
|
||||
vert.v = uv.y() + uv.height();
|
||||
vert.v = y_bottom;
|
||||
data.push_back(vert);
|
||||
|
||||
vert.x = (rect.x() + rect.width()) * 2 - 1;
|
||||
vert.y = rect.y() * 2 - 1;
|
||||
vert.u = uv.x() + uv.width();
|
||||
vert.v = uv.y();
|
||||
vert.v = y_top;
|
||||
data.push_back(vert);
|
||||
}
|
||||
|
||||
bool D3D11TextureHelper::UpdateVertexBuffer(LayerData& layer) {
|
||||
std::vector<Vertex2D> vertex_data;
|
||||
PushVertRect(vertex_data, target_left_, layer.left_, 0);
|
||||
PushVertRect(vertex_data, target_right_, layer.right_, 1);
|
||||
PushVertRect(vertex_data, target_left_, layer.left_, 0,
|
||||
backbuffer_y_flipped_);
|
||||
PushVertRect(vertex_data, target_right_, layer.right_, 1,
|
||||
backbuffer_y_flipped_);
|
||||
render_state_.d3d11_device_context_->UpdateSubresource(
|
||||
render_state_.vertex_buffer_.Get(), 0, nullptr, vertex_data.data(),
|
||||
sizeof(Vertex2D), vertex_data.size());
|
||||
@ -619,11 +630,15 @@ bool D3D11TextureHelper::UpdateBackbufferSizes() {
|
||||
}
|
||||
|
||||
void D3D11TextureHelper::SetBackbuffer(
|
||||
Microsoft::WRL::ComPtr<ID3D11Texture2D> back_buffer) {
|
||||
Microsoft::WRL::ComPtr<ID3D11Texture2D> back_buffer,
|
||||
bool contains_source,
|
||||
bool y_flipped) {
|
||||
if (render_state_.target_texture_ != back_buffer) {
|
||||
render_state_.render_target_view_ = nullptr;
|
||||
}
|
||||
render_state_.target_texture_ = back_buffer;
|
||||
backbuffer_contains_source_ = contains_source;
|
||||
backbuffer_y_flipped_ = y_flipped;
|
||||
}
|
||||
|
||||
Microsoft::WRL::ComPtr<IDXGIAdapter> D3D11TextureHelper::GetAdapter() {
|
||||
@ -646,6 +661,12 @@ Microsoft::WRL::ComPtr<ID3D11Device> D3D11TextureHelper::GetDevice() {
|
||||
return render_state_.d3d11_device_;
|
||||
}
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3D11DeviceContext>
|
||||
D3D11TextureHelper::GetDeviceContext() {
|
||||
EnsureInitialized();
|
||||
return render_state_.d3d11_device_context_;
|
||||
}
|
||||
|
||||
bool D3D11TextureHelper::EnsureInitialized() {
|
||||
if (render_state_.d3d11_device_ &&
|
||||
SUCCEEDED(render_state_.d3d11_device_->GetDeviceRemovedReason()))
|
||||
|
@ -35,6 +35,7 @@ class D3D11TextureHelper {
|
||||
|
||||
bool CompositeToBackBuffer(
|
||||
const scoped_refptr<viz::ContextProvider>& context_provider);
|
||||
|
||||
void SetSourceTexture(base::win::ScopedHandle texture_handle,
|
||||
const gpu::SyncToken& sync_token,
|
||||
gfx::RectF left,
|
||||
@ -51,8 +52,11 @@ class D3D11TextureHelper {
|
||||
force_viewport_ = true;
|
||||
}
|
||||
gfx::Size BackBufferSize() { return target_size_; }
|
||||
void SetBackbuffer(Microsoft::WRL::ComPtr<ID3D11Texture2D> back_buffer);
|
||||
void SetBackbuffer(Microsoft::WRL::ComPtr<ID3D11Texture2D> back_buffer,
|
||||
bool contains_source = false,
|
||||
bool y_flipped = false);
|
||||
Microsoft::WRL::ComPtr<ID3D11Device> GetDevice();
|
||||
Microsoft::WRL::ComPtr<ID3D11DeviceContext> GetDeviceContext();
|
||||
|
||||
void SetDefaultSize(gfx::Size size) { default_size_ = size; }
|
||||
|
||||
@ -114,6 +118,9 @@ class D3D11TextureHelper {
|
||||
bool bgra_ = false;
|
||||
bool force_viewport_ = false;
|
||||
|
||||
bool backbuffer_contains_source_ = false;
|
||||
bool backbuffer_y_flipped_ = false;
|
||||
|
||||
gfx::RectF target_left_; // 0 to 1 in each direction
|
||||
gfx::RectF target_right_; // 0 to 1 in each direction
|
||||
gfx::Size target_size_;
|
||||
|
Reference in New Issue
Block a user