xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/wgpu/SurfaceWgpu.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2024 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // SurfaceWgpu.cpp:
7 //    Implements the class methods for SurfaceWgpu.
8 //
9 
10 #include "libANGLE/renderer/wgpu/SurfaceWgpu.h"
11 
12 #include "common/debug.h"
13 
14 #include "libANGLE/Display.h"
15 #include "libANGLE/Surface.h"
16 #include "libANGLE/renderer/wgpu/DisplayWgpu.h"
17 #include "libANGLE/renderer/wgpu/FramebufferWgpu.h"
18 
19 namespace rx
20 {
21 
22 constexpr wgpu::TextureUsage kSurfaceTextureUsage =
23     wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment |
24     wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst;
25 
SurfaceWgpu(const egl::SurfaceState & surfaceState)26 SurfaceWgpu::SurfaceWgpu(const egl::SurfaceState &surfaceState) : SurfaceImpl(surfaceState) {}
27 
~SurfaceWgpu()28 SurfaceWgpu::~SurfaceWgpu() {}
29 
createDepthStencilAttachment(uint32_t width,uint32_t height,const webgpu::Format & webgpuFormat,wgpu::Device & device,AttachmentImage * outDepthStencilAttachment)30 angle::Result SurfaceWgpu::createDepthStencilAttachment(uint32_t width,
31                                                         uint32_t height,
32                                                         const webgpu::Format &webgpuFormat,
33                                                         wgpu::Device &device,
34                                                         AttachmentImage *outDepthStencilAttachment)
35 {
36     wgpu::TextureDescriptor desc = outDepthStencilAttachment->texture.createTextureDescriptor(
37         kSurfaceTextureUsage, wgpu::TextureDimension::e2D, {width, height, 1},
38         webgpuFormat.getActualWgpuTextureFormat(), 1, 1);
39 
40     constexpr uint32_t level = 0;
41     constexpr uint32_t layer = 0;
42 
43     ANGLE_TRY(outDepthStencilAttachment->texture.initImage(webgpuFormat.getIntendedFormatID(),
44                                                            webgpuFormat.getActualImageFormatID(),
45                                                            device, gl::LevelIndex(level), desc));
46 
47     wgpu::TextureView view;
48     ANGLE_TRY(
49         outDepthStencilAttachment->texture.createTextureView(gl::LevelIndex(level), layer, view));
50     outDepthStencilAttachment->renderTarget.set(
51         &outDepthStencilAttachment->texture, view, webgpu::LevelIndex(level), layer,
52         outDepthStencilAttachment->texture.toWgpuTextureFormat());
53     return angle::Result::Continue;
54 }
55 
OffscreenSurfaceWgpu(const egl::SurfaceState & surfaceState)56 OffscreenSurfaceWgpu::OffscreenSurfaceWgpu(const egl::SurfaceState &surfaceState)
57     : SurfaceWgpu(surfaceState),
58       mWidth(surfaceState.attributes.getAsInt(EGL_WIDTH, 0)),
59       mHeight(surfaceState.attributes.getAsInt(EGL_HEIGHT, 0))
60 {}
61 
~OffscreenSurfaceWgpu()62 OffscreenSurfaceWgpu::~OffscreenSurfaceWgpu() {}
63 
initialize(const egl::Display * display)64 egl::Error OffscreenSurfaceWgpu::initialize(const egl::Display *display)
65 {
66     return angle::ResultToEGL(initializeImpl(display));
67 }
68 
swap(const gl::Context * context)69 egl::Error OffscreenSurfaceWgpu::swap(const gl::Context *context)
70 {
71     UNREACHABLE();
72     return egl::NoError();
73 }
74 
bindTexImage(const gl::Context * context,gl::Texture * texture,EGLint buffer)75 egl::Error OffscreenSurfaceWgpu::bindTexImage(const gl::Context *context,
76                                               gl::Texture *texture,
77                                               EGLint buffer)
78 {
79     UNIMPLEMENTED();
80     return egl::NoError();
81 }
82 
releaseTexImage(const gl::Context * context,EGLint buffer)83 egl::Error OffscreenSurfaceWgpu::releaseTexImage(const gl::Context *context, EGLint buffer)
84 {
85     UNIMPLEMENTED();
86     return egl::NoError();
87 }
88 
setSwapInterval(const egl::Display * display,EGLint interval)89 void OffscreenSurfaceWgpu::setSwapInterval(const egl::Display *display, EGLint interval) {}
90 
getWidth() const91 EGLint OffscreenSurfaceWgpu::getWidth() const
92 {
93     return mWidth;
94 }
95 
getHeight() const96 EGLint OffscreenSurfaceWgpu::getHeight() const
97 {
98     return mHeight;
99 }
100 
getSwapBehavior() const101 EGLint OffscreenSurfaceWgpu::getSwapBehavior() const
102 {
103     return EGL_BUFFER_DESTROYED;
104 }
105 
initializeContents(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex)106 angle::Result OffscreenSurfaceWgpu::initializeContents(const gl::Context *context,
107                                                        GLenum binding,
108                                                        const gl::ImageIndex &imageIndex)
109 {
110     UNIMPLEMENTED();
111     return angle::Result::Continue;
112 }
113 
attachToFramebuffer(const gl::Context * context,gl::Framebuffer * framebuffer)114 egl::Error OffscreenSurfaceWgpu::attachToFramebuffer(const gl::Context *context,
115                                                      gl::Framebuffer *framebuffer)
116 {
117     UNIMPLEMENTED();
118     return egl::NoError();
119 }
120 
detachFromFramebuffer(const gl::Context * context,gl::Framebuffer * framebuffer)121 egl::Error OffscreenSurfaceWgpu::detachFromFramebuffer(const gl::Context *context,
122                                                        gl::Framebuffer *framebuffer)
123 {
124     UNIMPLEMENTED();
125     return egl::NoError();
126 }
127 
getAttachmentRenderTarget(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex,GLsizei samples,FramebufferAttachmentRenderTarget ** rtOut)128 angle::Result OffscreenSurfaceWgpu::getAttachmentRenderTarget(
129     const gl::Context *context,
130     GLenum binding,
131     const gl::ImageIndex &imageIndex,
132     GLsizei samples,
133     FramebufferAttachmentRenderTarget **rtOut)
134 {
135     if (binding == GL_BACK)
136     {
137         *rtOut = &mColorAttachment.renderTarget;
138     }
139     else
140     {
141         ASSERT(binding == GL_DEPTH || binding == GL_STENCIL || binding == GL_DEPTH_STENCIL);
142         *rtOut = &mDepthStencilAttachment.renderTarget;
143     }
144 
145     return angle::Result::Continue;
146 }
147 
initializeImpl(const egl::Display * display)148 angle::Result OffscreenSurfaceWgpu::initializeImpl(const egl::Display *display)
149 {
150     DisplayWgpu *displayWgpu = webgpu::GetImpl(display);
151     wgpu::Device &device     = displayWgpu->getDevice();
152 
153     const egl::Config *config = mState.config;
154 
155     if (config->renderTargetFormat != GL_NONE)
156     {
157         const webgpu::Format &webgpuFormat = displayWgpu->getFormat(config->renderTargetFormat);
158         wgpu::TextureDescriptor desc       = mColorAttachment.texture.createTextureDescriptor(
159             kSurfaceTextureUsage, wgpu::TextureDimension::e2D,
160             {static_cast<uint32_t>(mWidth), static_cast<uint32_t>(mHeight), 1},
161             webgpuFormat.getActualWgpuTextureFormat(), 1, 1);
162 
163         constexpr uint32_t level = 0;
164         constexpr uint32_t layer = 0;
165 
166         ANGLE_TRY(mColorAttachment.texture.initImage(webgpuFormat.getIntendedFormatID(),
167                                                      webgpuFormat.getActualImageFormatID(), device,
168                                                      gl::LevelIndex(level), desc));
169 
170         wgpu::TextureView view;
171         ANGLE_TRY(mColorAttachment.texture.createTextureView(gl::LevelIndex(level), layer, view));
172         mColorAttachment.renderTarget.set(&mColorAttachment.texture, view,
173                                           webgpu::LevelIndex(level), layer,
174                                           mColorAttachment.texture.toWgpuTextureFormat());
175     }
176 
177     if (config->depthStencilFormat != GL_NONE)
178     {
179         const webgpu::Format &webgpuFormat = displayWgpu->getFormat(config->depthStencilFormat);
180         ANGLE_TRY(createDepthStencilAttachment(static_cast<uint32_t>(mWidth),
181                                                static_cast<uint32_t>(mHeight), webgpuFormat, device,
182                                                &mDepthStencilAttachment));
183     }
184 
185     return angle::Result::Continue;
186 }
187 
WindowSurfaceWgpu(const egl::SurfaceState & surfaceState,EGLNativeWindowType window)188 WindowSurfaceWgpu::WindowSurfaceWgpu(const egl::SurfaceState &surfaceState,
189                                      EGLNativeWindowType window)
190     : SurfaceWgpu(surfaceState), mNativeWindow(window)
191 {}
192 
~WindowSurfaceWgpu()193 WindowSurfaceWgpu::~WindowSurfaceWgpu() {}
194 
initialize(const egl::Display * display)195 egl::Error WindowSurfaceWgpu::initialize(const egl::Display *display)
196 {
197     return angle::ResultToEGL(initializeImpl(display));
198 }
199 
destroy(const egl::Display * display)200 void WindowSurfaceWgpu::destroy(const egl::Display *display)
201 {
202     mSurface   = nullptr;
203     mColorAttachment.renderTarget.reset();
204     mColorAttachment.texture.resetImage();
205     mDepthStencilAttachment.renderTarget.reset();
206     mDepthStencilAttachment.texture.resetImage();
207 }
208 
swap(const gl::Context * context)209 egl::Error WindowSurfaceWgpu::swap(const gl::Context *context)
210 {
211     return angle::ResultToEGL(swapImpl(context));
212 }
213 
bindTexImage(const gl::Context * context,gl::Texture * texture,EGLint buffer)214 egl::Error WindowSurfaceWgpu::bindTexImage(const gl::Context *context,
215                                            gl::Texture *texture,
216                                            EGLint buffer)
217 {
218     UNIMPLEMENTED();
219     return egl::NoError();
220 }
221 
releaseTexImage(const gl::Context * context,EGLint buffer)222 egl::Error WindowSurfaceWgpu::releaseTexImage(const gl::Context *context, EGLint buffer)
223 {
224     UNIMPLEMENTED();
225     return egl::NoError();
226 }
227 
setSwapInterval(const egl::Display * display,EGLint interval)228 void WindowSurfaceWgpu::setSwapInterval(const egl::Display *display, EGLint interval)
229 {
230     UNIMPLEMENTED();
231 }
232 
getWidth() const233 EGLint WindowSurfaceWgpu::getWidth() const
234 {
235     return mCurrentSurfaceSize.width;
236 }
237 
getHeight() const238 EGLint WindowSurfaceWgpu::getHeight() const
239 {
240     return mCurrentSurfaceSize.height;
241 }
242 
getSwapBehavior() const243 EGLint WindowSurfaceWgpu::getSwapBehavior() const
244 {
245     UNIMPLEMENTED();
246     return 0;
247 }
248 
initializeContents(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex)249 angle::Result WindowSurfaceWgpu::initializeContents(const gl::Context *context,
250                                                     GLenum binding,
251                                                     const gl::ImageIndex &imageIndex)
252 {
253     UNIMPLEMENTED();
254     return angle::Result::Continue;
255 }
256 
attachToFramebuffer(const gl::Context * context,gl::Framebuffer * framebuffer)257 egl::Error WindowSurfaceWgpu::attachToFramebuffer(const gl::Context *context,
258                                                   gl::Framebuffer *framebuffer)
259 {
260     return egl::NoError();
261 }
262 
detachFromFramebuffer(const gl::Context * context,gl::Framebuffer * framebuffer)263 egl::Error WindowSurfaceWgpu::detachFromFramebuffer(const gl::Context *context,
264                                                     gl::Framebuffer *framebuffer)
265 {
266     return egl::NoError();
267 }
268 
getAttachmentRenderTarget(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex,GLsizei samples,FramebufferAttachmentRenderTarget ** rtOut)269 angle::Result WindowSurfaceWgpu::getAttachmentRenderTarget(
270     const gl::Context *context,
271     GLenum binding,
272     const gl::ImageIndex &imageIndex,
273     GLsizei samples,
274     FramebufferAttachmentRenderTarget **rtOut)
275 {
276     if (binding == GL_BACK)
277     {
278         *rtOut = &mColorAttachment.renderTarget;
279     }
280     else
281     {
282         ASSERT(binding == GL_DEPTH || binding == GL_STENCIL || binding == GL_DEPTH_STENCIL);
283         *rtOut = &mDepthStencilAttachment.renderTarget;
284     }
285 
286     return angle::Result::Continue;
287 }
288 
initializeImpl(const egl::Display * display)289 angle::Result WindowSurfaceWgpu::initializeImpl(const egl::Display *display)
290 {
291     DisplayWgpu *displayWgpu = webgpu::GetImpl(display);
292     wgpu::Adapter &adapter   = displayWgpu->getAdapter();
293 
294     ANGLE_TRY(createWgpuSurface(display, &mSurface));
295 
296     gl::Extents size;
297     ANGLE_TRY(getCurrentWindowSize(display, &size));
298 
299     wgpu::SurfaceCapabilities surfaceCapabilities;
300     wgpu::Status getCapabilitiesStatus = mSurface.GetCapabilities(adapter, &surfaceCapabilities);
301     if (getCapabilitiesStatus != wgpu::Status::Success)
302     {
303         ERR() << "wgpu::Surface::GetCapabilities failed: "
304               << gl::FmtHex(static_cast<uint32_t>(getCapabilitiesStatus));
305         return angle::Result::Stop;
306     }
307 
308     const egl::Config *config = mState.config;
309     ASSERT(config->renderTargetFormat != GL_NONE);
310     mSurfaceTextureFormat = &displayWgpu->getFormat(config->renderTargetFormat);
311     ASSERT(std::find(surfaceCapabilities.formats,
312                      surfaceCapabilities.formats + surfaceCapabilities.formatCount,
313                      mSurfaceTextureFormat->getActualWgpuTextureFormat()) !=
314            (surfaceCapabilities.formats + surfaceCapabilities.formatCount));
315 
316     mSurfaceTextureUsage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc |
317                            wgpu::TextureUsage::CopyDst;
318     ASSERT((surfaceCapabilities.usages & mSurfaceTextureUsage) == mSurfaceTextureUsage);
319 
320     // Default to the always supported Fifo present mode. Use Mailbox if it's available.
321     mPresentMode = wgpu::PresentMode::Fifo;
322     for (size_t i = 0; i < surfaceCapabilities.presentModeCount; i++)
323     {
324         if (surfaceCapabilities.presentModes[i] == wgpu::PresentMode::Mailbox)
325         {
326             mPresentMode = wgpu::PresentMode::Mailbox;
327         }
328     }
329 
330     if (config->depthStencilFormat != GL_NONE)
331     {
332         mDepthStencilFormat = &displayWgpu->getFormat(config->depthStencilFormat);
333     }
334     else
335     {
336         mDepthStencilFormat = nullptr;
337     }
338 
339     ANGLE_TRY(configureSurface(display, size));
340     ANGLE_TRY(updateCurrentTexture(display));
341 
342     return angle::Result::Continue;
343 }
344 
swapImpl(const gl::Context * context)345 angle::Result WindowSurfaceWgpu::swapImpl(const gl::Context *context)
346 {
347     const egl::Display *display = context->getDisplay();
348     ContextWgpu *contextWgpu    = webgpu::GetImpl(context);
349 
350     ANGLE_TRY(contextWgpu->flush(webgpu::RenderPassClosureReason::EGLSwapBuffers));
351 
352     mSurface.Present();
353 
354     gl::Extents size;
355     ANGLE_TRY(getCurrentWindowSize(display, &size));
356     if (size != mCurrentSurfaceSize)
357     {
358         ANGLE_TRY(configureSurface(display, size));
359     }
360 
361     ANGLE_TRY(updateCurrentTexture(display));
362 
363     return angle::Result::Continue;
364 }
365 
configureSurface(const egl::Display * display,const gl::Extents & size)366 angle::Result WindowSurfaceWgpu::configureSurface(const egl::Display *display,
367                                                   const gl::Extents &size)
368 {
369     DisplayWgpu *displayWgpu = webgpu::GetImpl(display);
370     wgpu::Device &device     = displayWgpu->getDevice();
371 
372     ASSERT(mSurfaceTextureFormat != nullptr);
373 
374     wgpu::SurfaceConfiguration surfaceConfig = {};
375     surfaceConfig.device                     = device;
376     surfaceConfig.format                     = mSurfaceTextureFormat->getActualWgpuTextureFormat();
377     surfaceConfig.usage                      = mSurfaceTextureUsage;
378     surfaceConfig.width                      = size.width;
379     surfaceConfig.height                     = size.height;
380     surfaceConfig.presentMode                = mPresentMode;
381 
382     mSurface.Configure(&surfaceConfig);
383 
384     if (mDepthStencilFormat)
385     {
386         ANGLE_TRY(createDepthStencilAttachment(
387             static_cast<uint32_t>(size.width), static_cast<uint32_t>(size.height),
388             *mDepthStencilFormat, device, &mDepthStencilAttachment));
389     }
390 
391     mCurrentSurfaceSize = size;
392     return angle::Result::Continue;
393 }
394 
updateCurrentTexture(const egl::Display * display)395 angle::Result WindowSurfaceWgpu::updateCurrentTexture(const egl::Display *display)
396 {
397     wgpu::SurfaceTexture texture;
398     mSurface.GetCurrentTexture(&texture);
399     if (texture.status != wgpu::SurfaceGetCurrentTextureStatus::Success)
400     {
401         ERR() << "wgpu::Surface::GetCurrentTexture failed: "
402               << gl::FmtHex(static_cast<uint32_t>(texture.status));
403         return angle::Result::Stop;
404     }
405 
406     wgpu::TextureFormat wgpuFormat = texture.texture.GetFormat();
407     angle::FormatID angleFormat    = webgpu::GetFormatIDFromWgpuTextureFormat(wgpuFormat);
408 
409     ANGLE_TRY(mColorAttachment.texture.initExternal(angleFormat, angleFormat, texture.texture));
410 
411     wgpu::TextureView view;
412     ANGLE_TRY(mColorAttachment.texture.createTextureView(gl::LevelIndex(0), 0, view));
413 
414     mColorAttachment.renderTarget.set(&mColorAttachment.texture, view, webgpu::LevelIndex(0), 0,
415                                       wgpuFormat);
416 
417     return angle::Result::Continue;
418 }
419 
420 }  // namespace rx
421