blob: f71e792f2af2c9ab2747551eea9f220439ec00b0 [file] [log] [blame]
//
// Copyright 2024 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// SurfaceWgpu.cpp:
// Implements the class methods for SurfaceWgpu.
//
#include "libANGLE/renderer/wgpu/SurfaceWgpu.h"
#include "common/debug.h"
#include "libANGLE/Display.h"
#include "libANGLE/Surface.h"
#include "libANGLE/renderer/wgpu/DisplayWgpu.h"
#include "libANGLE/renderer/wgpu/FramebufferWgpu.h"
namespace rx
{
constexpr wgpu::TextureUsage kSurfaceTextureUsage =
wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment |
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst;
SurfaceWgpu::SurfaceWgpu(const egl::SurfaceState &surfaceState) : SurfaceImpl(surfaceState) {}
SurfaceWgpu::~SurfaceWgpu() {}
angle::Result SurfaceWgpu::createDepthStencilAttachment(uint32_t width,
uint32_t height,
const webgpu::Format &webgpuFormat,
wgpu::Device &device,
AttachmentImage *outDepthStencilAttachment)
{
wgpu::TextureDescriptor desc = outDepthStencilAttachment->texture.createTextureDescriptor(
kSurfaceTextureUsage, wgpu::TextureDimension::e2D, {width, height, 1},
webgpuFormat.getActualWgpuTextureFormat(), 1, 1);
constexpr uint32_t level = 0;
constexpr uint32_t layer = 0;
ANGLE_TRY(outDepthStencilAttachment->texture.initImage(webgpuFormat.getIntendedFormatID(),
webgpuFormat.getActualImageFormatID(),
device, gl::LevelIndex(level), desc));
wgpu::TextureView view;
ANGLE_TRY(
outDepthStencilAttachment->texture.createTextureView(gl::LevelIndex(level), layer, view));
outDepthStencilAttachment->renderTarget.set(
&outDepthStencilAttachment->texture, view, webgpu::LevelIndex(level), layer,
outDepthStencilAttachment->texture.toWgpuTextureFormat());
return angle::Result::Continue;
}
OffscreenSurfaceWgpu::OffscreenSurfaceWgpu(const egl::SurfaceState &surfaceState)
: SurfaceWgpu(surfaceState),
mWidth(surfaceState.attributes.getAsInt(EGL_WIDTH, 0)),
mHeight(surfaceState.attributes.getAsInt(EGL_HEIGHT, 0))
{}
OffscreenSurfaceWgpu::~OffscreenSurfaceWgpu() {}
egl::Error OffscreenSurfaceWgpu::initialize(const egl::Display *display)
{
return angle::ResultToEGL(initializeImpl(display));
}
egl::Error OffscreenSurfaceWgpu::swap(const gl::Context *context)
{
UNREACHABLE();
return egl::NoError();
}
egl::Error OffscreenSurfaceWgpu::bindTexImage(const gl::Context *context,
gl::Texture *texture,
EGLint buffer)
{
UNIMPLEMENTED();
return egl::NoError();
}
egl::Error OffscreenSurfaceWgpu::releaseTexImage(const gl::Context *context, EGLint buffer)
{
UNIMPLEMENTED();
return egl::NoError();
}
void OffscreenSurfaceWgpu::setSwapInterval(const egl::Display *display, EGLint interval) {}
EGLint OffscreenSurfaceWgpu::getWidth() const
{
return mWidth;
}
EGLint OffscreenSurfaceWgpu::getHeight() const
{
return mHeight;
}
EGLint OffscreenSurfaceWgpu::getSwapBehavior() const
{
return EGL_BUFFER_DESTROYED;
}
angle::Result OffscreenSurfaceWgpu::initializeContents(const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex)
{
UNIMPLEMENTED();
return angle::Result::Continue;
}
egl::Error OffscreenSurfaceWgpu::attachToFramebuffer(const gl::Context *context,
gl::Framebuffer *framebuffer)
{
UNIMPLEMENTED();
return egl::NoError();
}
egl::Error OffscreenSurfaceWgpu::detachFromFramebuffer(const gl::Context *context,
gl::Framebuffer *framebuffer)
{
UNIMPLEMENTED();
return egl::NoError();
}
angle::Result OffscreenSurfaceWgpu::getAttachmentRenderTarget(
const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex,
GLsizei samples,
FramebufferAttachmentRenderTarget **rtOut)
{
if (binding == GL_BACK)
{
*rtOut = &mColorAttachment.renderTarget;
}
else
{
ASSERT(binding == GL_DEPTH || binding == GL_STENCIL || binding == GL_DEPTH_STENCIL);
*rtOut = &mDepthStencilAttachment.renderTarget;
}
return angle::Result::Continue;
}
angle::Result OffscreenSurfaceWgpu::initializeImpl(const egl::Display *display)
{
DisplayWgpu *displayWgpu = webgpu::GetImpl(display);
wgpu::Device &device = displayWgpu->getDevice();
const egl::Config *config = mState.config;
if (config->renderTargetFormat != GL_NONE)
{
const webgpu::Format &webgpuFormat = displayWgpu->getFormat(config->renderTargetFormat);
wgpu::TextureDescriptor desc = mColorAttachment.texture.createTextureDescriptor(
kSurfaceTextureUsage, wgpu::TextureDimension::e2D,
{static_cast<uint32_t>(mWidth), static_cast<uint32_t>(mHeight), 1},
webgpuFormat.getActualWgpuTextureFormat(), 1, 1);
constexpr uint32_t level = 0;
constexpr uint32_t layer = 0;
ANGLE_TRY(mColorAttachment.texture.initImage(webgpuFormat.getIntendedFormatID(),
webgpuFormat.getActualImageFormatID(), device,
gl::LevelIndex(level), desc));
wgpu::TextureView view;
ANGLE_TRY(mColorAttachment.texture.createTextureView(gl::LevelIndex(level), layer, view));
mColorAttachment.renderTarget.set(&mColorAttachment.texture, view,
webgpu::LevelIndex(level), layer,
mColorAttachment.texture.toWgpuTextureFormat());
}
if (config->depthStencilFormat != GL_NONE)
{
const webgpu::Format &webgpuFormat = displayWgpu->getFormat(config->depthStencilFormat);
ANGLE_TRY(createDepthStencilAttachment(static_cast<uint32_t>(mWidth),
static_cast<uint32_t>(mHeight), webgpuFormat, device,
&mDepthStencilAttachment));
}
return angle::Result::Continue;
}
WindowSurfaceWgpu::WindowSurfaceWgpu(const egl::SurfaceState &surfaceState,
EGLNativeWindowType window)
: SurfaceWgpu(surfaceState), mNativeWindow(window)
{}
WindowSurfaceWgpu::~WindowSurfaceWgpu() {}
egl::Error WindowSurfaceWgpu::initialize(const egl::Display *display)
{
return angle::ResultToEGL(initializeImpl(display));
}
void WindowSurfaceWgpu::destroy(const egl::Display *display)
{
mSurface = nullptr;
mColorAttachment.renderTarget.reset();
mColorAttachment.texture.resetImage();
mDepthStencilAttachment.renderTarget.reset();
mDepthStencilAttachment.texture.resetImage();
}
egl::Error WindowSurfaceWgpu::swap(const gl::Context *context)
{
return angle::ResultToEGL(swapImpl(context));
}
egl::Error WindowSurfaceWgpu::bindTexImage(const gl::Context *context,
gl::Texture *texture,
EGLint buffer)
{
UNIMPLEMENTED();
return egl::NoError();
}
egl::Error WindowSurfaceWgpu::releaseTexImage(const gl::Context *context, EGLint buffer)
{
UNIMPLEMENTED();
return egl::NoError();
}
void WindowSurfaceWgpu::setSwapInterval(const egl::Display *display, EGLint interval)
{
UNIMPLEMENTED();
}
EGLint WindowSurfaceWgpu::getWidth() const
{
return mCurrentSurfaceSize.width;
}
EGLint WindowSurfaceWgpu::getHeight() const
{
return mCurrentSurfaceSize.height;
}
EGLint WindowSurfaceWgpu::getSwapBehavior() const
{
UNIMPLEMENTED();
return 0;
}
angle::Result WindowSurfaceWgpu::initializeContents(const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex)
{
UNIMPLEMENTED();
return angle::Result::Continue;
}
egl::Error WindowSurfaceWgpu::attachToFramebuffer(const gl::Context *context,
gl::Framebuffer *framebuffer)
{
return egl::NoError();
}
egl::Error WindowSurfaceWgpu::detachFromFramebuffer(const gl::Context *context,
gl::Framebuffer *framebuffer)
{
return egl::NoError();
}
angle::Result WindowSurfaceWgpu::getAttachmentRenderTarget(
const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex,
GLsizei samples,
FramebufferAttachmentRenderTarget **rtOut)
{
if (binding == GL_BACK)
{
*rtOut = &mColorAttachment.renderTarget;
}
else
{
ASSERT(binding == GL_DEPTH || binding == GL_STENCIL || binding == GL_DEPTH_STENCIL);
*rtOut = &mDepthStencilAttachment.renderTarget;
}
return angle::Result::Continue;
}
angle::Result WindowSurfaceWgpu::initializeImpl(const egl::Display *display)
{
DisplayWgpu *displayWgpu = webgpu::GetImpl(display);
wgpu::Adapter &adapter = displayWgpu->getAdapter();
ANGLE_TRY(createWgpuSurface(display, &mSurface));
gl::Extents size;
ANGLE_TRY(getCurrentWindowSize(display, &size));
wgpu::SurfaceCapabilities surfaceCapabilities;
wgpu::Status getCapabilitiesStatus = mSurface.GetCapabilities(adapter, &surfaceCapabilities);
if (getCapabilitiesStatus != wgpu::Status::Success)
{
ERR() << "wgpu::Surface::GetCapabilities failed: "
<< gl::FmtHex(static_cast<uint32_t>(getCapabilitiesStatus));
return angle::Result::Stop;
}
const egl::Config *config = mState.config;
ASSERT(config->renderTargetFormat != GL_NONE);
mSurfaceTextureFormat = &displayWgpu->getFormat(config->renderTargetFormat);
ASSERT(std::find(surfaceCapabilities.formats,
surfaceCapabilities.formats + surfaceCapabilities.formatCount,
mSurfaceTextureFormat->getActualWgpuTextureFormat()) !=
(surfaceCapabilities.formats + surfaceCapabilities.formatCount));
mSurfaceTextureUsage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc |
wgpu::TextureUsage::CopyDst;
ASSERT((surfaceCapabilities.usages & mSurfaceTextureUsage) == mSurfaceTextureUsage);
// Default to the always supported Fifo present mode. Use Mailbox if it's available.
mPresentMode = wgpu::PresentMode::Fifo;
for (size_t i = 0; i < surfaceCapabilities.presentModeCount; i++)
{
if (surfaceCapabilities.presentModes[i] == wgpu::PresentMode::Mailbox)
{
mPresentMode = wgpu::PresentMode::Mailbox;
}
}
if (config->depthStencilFormat != GL_NONE)
{
mDepthStencilFormat = &displayWgpu->getFormat(config->depthStencilFormat);
}
else
{
mDepthStencilFormat = nullptr;
}
ANGLE_TRY(configureSurface(display, size));
ANGLE_TRY(updateCurrentTexture(display));
return angle::Result::Continue;
}
angle::Result WindowSurfaceWgpu::swapImpl(const gl::Context *context)
{
const egl::Display *display = context->getDisplay();
ContextWgpu *contextWgpu = webgpu::GetImpl(context);
ANGLE_TRY(contextWgpu->flush(webgpu::RenderPassClosureReason::EGLSwapBuffers));
mSurface.Present();
gl::Extents size;
ANGLE_TRY(getCurrentWindowSize(display, &size));
if (size != mCurrentSurfaceSize)
{
ANGLE_TRY(configureSurface(display, size));
}
ANGLE_TRY(updateCurrentTexture(display));
return angle::Result::Continue;
}
angle::Result WindowSurfaceWgpu::configureSurface(const egl::Display *display,
const gl::Extents &size)
{
DisplayWgpu *displayWgpu = webgpu::GetImpl(display);
wgpu::Device &device = displayWgpu->getDevice();
ASSERT(mSurfaceTextureFormat != nullptr);
wgpu::SurfaceConfiguration surfaceConfig = {};
surfaceConfig.device = device;
surfaceConfig.format = mSurfaceTextureFormat->getActualWgpuTextureFormat();
surfaceConfig.usage = mSurfaceTextureUsage;
surfaceConfig.width = size.width;
surfaceConfig.height = size.height;
surfaceConfig.presentMode = mPresentMode;
mSurface.Configure(&surfaceConfig);
if (mDepthStencilFormat)
{
ANGLE_TRY(createDepthStencilAttachment(
static_cast<uint32_t>(size.width), static_cast<uint32_t>(size.height),
*mDepthStencilFormat, device, &mDepthStencilAttachment));
}
mCurrentSurfaceSize = size;
return angle::Result::Continue;
}
angle::Result WindowSurfaceWgpu::updateCurrentTexture(const egl::Display *display)
{
wgpu::SurfaceTexture texture;
mSurface.GetCurrentTexture(&texture);
if (texture.status != wgpu::SurfaceGetCurrentTextureStatus::SuccessOptimal &&
texture.status != wgpu::SurfaceGetCurrentTextureStatus::SuccessSuboptimal)
{
ERR() << "wgpu::Surface::GetCurrentTexture failed: "
<< gl::FmtHex(static_cast<uint32_t>(texture.status));
return angle::Result::Stop;
}
wgpu::TextureFormat wgpuFormat = texture.texture.GetFormat();
angle::FormatID angleFormat = webgpu::GetFormatIDFromWgpuTextureFormat(wgpuFormat);
ANGLE_TRY(mColorAttachment.texture.initExternal(angleFormat, angleFormat, texture.texture));
wgpu::TextureView view;
ANGLE_TRY(mColorAttachment.texture.createTextureView(gl::LevelIndex(0), 0, view));
mColorAttachment.renderTarget.set(&mColorAttachment.texture, view, webgpu::LevelIndex(0), 0,
wgpuFormat);
return angle::Result::Continue;
}
} // namespace rx