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