xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/vulkan/RenderbufferVk.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2016 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 // RenderbufferVk.cpp:
7 //    Implements the class methods for RenderbufferVk.
8 //
9 
10 #include "libANGLE/renderer/vulkan/RenderbufferVk.h"
11 
12 #include "libANGLE/Context.h"
13 #include "libANGLE/Image.h"
14 #include "libANGLE/renderer/vulkan/ContextVk.h"
15 #include "libANGLE/renderer/vulkan/ImageVk.h"
16 #include "libANGLE/renderer/vulkan/TextureVk.h"
17 #include "libANGLE/renderer/vulkan/vk_renderer.h"
18 
19 namespace rx
20 {
21 namespace
22 {
23 angle::SubjectIndex kRenderbufferImageSubjectIndex = 0;
24 }  // namespace
25 
RenderbufferVk(const gl::RenderbufferState & state)26 RenderbufferVk::RenderbufferVk(const gl::RenderbufferState &state)
27     : RenderbufferImpl(state),
28       mOwnsImage(false),
29       mImage(nullptr),
30       mImageObserverBinding(this, kRenderbufferImageSubjectIndex)
31 {}
32 
~RenderbufferVk()33 RenderbufferVk::~RenderbufferVk() {}
34 
onDestroy(const gl::Context * context)35 void RenderbufferVk::onDestroy(const gl::Context *context)
36 {
37     ContextVk *contextVk = vk::GetImpl(context);
38     releaseAndDeleteImage(contextVk);
39 }
40 
setStorageImpl(const gl::Context * context,GLsizei samples,GLenum internalformat,GLsizei width,GLsizei height,gl::MultisamplingMode mode)41 angle::Result RenderbufferVk::setStorageImpl(const gl::Context *context,
42                                              GLsizei samples,
43                                              GLenum internalformat,
44                                              GLsizei width,
45                                              GLsizei height,
46                                              gl::MultisamplingMode mode)
47 {
48     ContextVk *contextVk            = vk::GetImpl(context);
49     vk::Renderer *renderer          = contextVk->getRenderer();
50     const vk::Format &format        = renderer->getFormat(internalformat);
51     angle::FormatID textureFormatID = format.getActualRenderableImageFormatID();
52 
53     if (!mOwnsImage)
54     {
55         releaseAndDeleteImage(contextVk);
56     }
57 
58     if (mImage != nullptr && mImage->valid())
59     {
60         // Check against the state if we need to recreate the storage.
61         if (internalformat != mState.getFormat().info->internalFormat ||
62             width != mState.getWidth() || height != mState.getHeight() ||
63             samples != mState.getSamples() || mode != mState.getMultisamplingMode())
64         {
65             releaseImage(contextVk);
66         }
67     }
68 
69     if ((mImage != nullptr && mImage->valid()) || width == 0 || height == 0)
70     {
71         return angle::Result::Continue;
72     }
73 
74     if (mImage == nullptr)
75     {
76         mImage              = new vk::ImageHelper();
77         mOwnsImage          = true;
78         mImageSiblingSerial = {};
79         mImageObserverBinding.bind(mImage);
80         mImageViews.init(renderer);
81     }
82 
83     const angle::Format &textureFormat = format.getActualRenderableImageFormat();
84     const bool isDepthStencilFormat    = textureFormat.hasDepthOrStencilBits();
85     ASSERT(textureFormat.redBits > 0 || isDepthStencilFormat);
86 
87     const bool isRenderToTexture = mode == gl::MultisamplingMode::MultisampledRenderToTexture;
88     const bool hasRenderToTextureEXT =
89         renderer->getFeatures().supportsMultisampledRenderToSingleSampled.enabled;
90 
91     // Transfer and sampled usage are used for various utilities such as readback or blit.
92     VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
93                               VK_IMAGE_USAGE_SAMPLED_BIT;
94 
95     // Renderbuffer's normal usage is as framebuffer attachment.
96     usage |= isDepthStencilFormat ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
97                                   : VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
98 
99     // When used to emulate multisampled render to texture, it can be read as input attachment.
100     if (isRenderToTexture && !hasRenderToTextureEXT)
101     {
102         usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
103     }
104 
105     // For framebuffer fetch and advanced blend emulation, color will be read as input attachment.
106     // For depth/stencil framebuffer fetch, depth/stencil will also be read as input attachment.
107     if (!isDepthStencilFormat ||
108         renderer->getFeatures().supportsShaderFramebufferFetchDepthStencil.enabled)
109     {
110         usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
111     }
112 
113     VkImageCreateFlags createFlags = vk::kVkImageCreateFlagsNone;
114     if (isRenderToTexture &&
115         renderer->getFeatures().supportsMultisampledRenderToSingleSampled.enabled)
116     {
117         createFlags |= VK_IMAGE_CREATE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_BIT_EXT;
118     }
119 
120     if (contextVk->getFeatures().limitSampleCountTo2.enabled)
121     {
122         samples = std::min(samples, 2);
123     }
124 
125     const uint32_t imageSamples = isRenderToTexture ? 1 : samples;
126 
127     bool robustInit = contextVk->isRobustResourceInitEnabled();
128 
129     VkExtent3D extents = {static_cast<uint32_t>(width), static_cast<uint32_t>(height), 1u};
130     ANGLE_TRY(mImage->initExternal(
131         contextVk, gl::TextureType::_2D, extents, format.getIntendedFormatID(), textureFormatID,
132         imageSamples, usage, createFlags, vk::ImageLayout::Undefined, nullptr, gl::LevelIndex(0), 1,
133         1, robustInit, false, vk::YcbcrConversionDesc{}, nullptr));
134 
135     VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
136     ANGLE_TRY(contextVk->initImageAllocation(mImage, false, renderer->getMemoryProperties(), flags,
137                                              vk::MemoryAllocationType::RenderBufferStorageImage));
138 
139     // If multisampled render to texture, an implicit multisampled image is created which is used as
140     // the color or depth/stencil attachment.  At the end of the render pass, this image is
141     // automatically resolved into |mImage| and its contents are discarded.
142     if (isRenderToTexture && !hasRenderToTextureEXT)
143     {
144         mMultisampledImageViews.init(renderer);
145 
146         ANGLE_TRY(mMultisampledImage.initImplicitMultisampledRenderToTexture(
147             contextVk, false, renderer->getMemoryProperties(), gl::TextureType::_2D, samples,
148             *mImage, mImage->getExtents(), robustInit));
149 
150         mRenderTarget.init(&mMultisampledImage, &mMultisampledImageViews, mImage, &mImageViews,
151                            mImageSiblingSerial, gl::LevelIndex(0), 0, 1,
152                            RenderTargetTransience::MultisampledTransient);
153     }
154     else
155     {
156         mRenderTarget.init(mImage, &mImageViews, nullptr, nullptr, mImageSiblingSerial,
157                            gl::LevelIndex(0), 0, 1, RenderTargetTransience::Default);
158     }
159 
160     return angle::Result::Continue;
161 }
162 
setStorage(const gl::Context * context,GLenum internalformat,GLsizei width,GLsizei height)163 angle::Result RenderbufferVk::setStorage(const gl::Context *context,
164                                          GLenum internalformat,
165                                          GLsizei width,
166                                          GLsizei height)
167 {
168     // The ES 3.0 spec(section 4.4.2.1) states that RenderbufferStorage is equivalent to calling
169     // RenderbufferStorageMultisample with samples equal to zero.
170     return setStorageImpl(context, 0, internalformat, width, height,
171                           gl::MultisamplingMode::Regular);
172 }
173 
setStorageMultisample(const gl::Context * context,GLsizei samples,GLenum internalformat,GLsizei width,GLsizei height,gl::MultisamplingMode mode)174 angle::Result RenderbufferVk::setStorageMultisample(const gl::Context *context,
175                                                     GLsizei samples,
176                                                     GLenum internalformat,
177                                                     GLsizei width,
178                                                     GLsizei height,
179                                                     gl::MultisamplingMode mode)
180 {
181     return setStorageImpl(context, samples, internalformat, width, height, mode);
182 }
183 
setStorageEGLImageTarget(const gl::Context * context,egl::Image * image)184 angle::Result RenderbufferVk::setStorageEGLImageTarget(const gl::Context *context,
185                                                        egl::Image *image)
186 {
187     ContextVk *contextVk   = vk::GetImpl(context);
188     vk::Renderer *renderer = contextVk->getRenderer();
189 
190     ANGLE_TRY(contextVk->getShareGroup()->lockDefaultContextsPriority(contextVk));
191 
192     releaseAndDeleteImage(contextVk);
193 
194     ImageVk *imageVk    = vk::GetImpl(image);
195     mImage              = imageVk->getImage();
196     mOwnsImage          = false;
197     mImageSiblingSerial = imageVk->generateSiblingSerial();
198     mImageObserverBinding.bind(mImage);
199     mImageViews.init(renderer);
200 
201     // Update ImageViewHelper's colorspace related state
202     EGLenum imageColorspaceAttribute = image->getColorspaceAttribute();
203     if (imageColorspaceAttribute != EGL_GL_COLORSPACE_DEFAULT_EXT)
204     {
205         egl::ImageColorspace imageColorspace =
206             (imageColorspaceAttribute == EGL_GL_COLORSPACE_SRGB_KHR) ? egl::ImageColorspace::SRGB
207                                                                      : egl::ImageColorspace::Linear;
208         ASSERT(mImage != nullptr);
209         mImageViews.updateEglImageColorspace(*mImage, imageColorspace);
210     }
211 
212     // Transfer the image to this queue if needed
213     if (mImage->isQueueFamilyChangeNeccesary(contextVk->getDeviceQueueIndex()))
214     {
215         vk::OutsideRenderPassCommandBuffer *commandBuffer;
216         vk::CommandBufferAccess access;
217         access.onExternalAcquireRelease(mImage);
218         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
219 
220         const vk::Format &vkFormat =
221             renderer->getFormat(image->getFormat().info->sizedInternalFormat);
222         const angle::Format &textureFormat = vkFormat.getActualRenderableImageFormat();
223         VkImageAspectFlags aspect          = vk::GetFormatAspectFlags(textureFormat);
224 
225         mImage->changeLayoutAndQueue(contextVk, aspect, vk::ImageLayout::ColorWrite,
226                                      contextVk->getDeviceQueueIndex(), commandBuffer);
227 
228         ANGLE_TRY(contextVk->onEGLImageQueueChange());
229     }
230 
231     mRenderTarget.init(mImage, &mImageViews, nullptr, nullptr, mImageSiblingSerial,
232                        imageVk->getImageLevel(), imageVk->getImageLayer(), 1,
233                        RenderTargetTransience::Default);
234 
235     return angle::Result::Continue;
236 }
237 
copyRenderbufferSubData(const gl::Context * context,const gl::Renderbuffer * srcBuffer,GLint srcLevel,GLint srcX,GLint srcY,GLint srcZ,GLint dstLevel,GLint dstX,GLint dstY,GLint dstZ,GLsizei srcWidth,GLsizei srcHeight,GLsizei srcDepth)238 angle::Result RenderbufferVk::copyRenderbufferSubData(const gl::Context *context,
239                                                       const gl::Renderbuffer *srcBuffer,
240                                                       GLint srcLevel,
241                                                       GLint srcX,
242                                                       GLint srcY,
243                                                       GLint srcZ,
244                                                       GLint dstLevel,
245                                                       GLint dstX,
246                                                       GLint dstY,
247                                                       GLint dstZ,
248                                                       GLsizei srcWidth,
249                                                       GLsizei srcHeight,
250                                                       GLsizei srcDepth)
251 {
252     RenderbufferVk *sourceVk = vk::GetImpl(srcBuffer);
253 
254     // Make sure the source/destination targets are initialized and all staged updates are flushed.
255     ANGLE_TRY(sourceVk->ensureImageInitialized(context));
256     ANGLE_TRY(ensureImageInitialized(context));
257 
258     return vk::ImageHelper::CopyImageSubData(context, sourceVk->getImage(), srcLevel, srcX, srcY,
259                                              srcZ, mImage, dstLevel, dstX, dstY, dstZ, srcWidth,
260                                              srcHeight, srcDepth);
261 }
262 
copyTextureSubData(const gl::Context * context,const gl::Texture * srcTexture,GLint srcLevel,GLint srcX,GLint srcY,GLint srcZ,GLint dstLevel,GLint dstX,GLint dstY,GLint dstZ,GLsizei srcWidth,GLsizei srcHeight,GLsizei srcDepth)263 angle::Result RenderbufferVk::copyTextureSubData(const gl::Context *context,
264                                                  const gl::Texture *srcTexture,
265                                                  GLint srcLevel,
266                                                  GLint srcX,
267                                                  GLint srcY,
268                                                  GLint srcZ,
269                                                  GLint dstLevel,
270                                                  GLint dstX,
271                                                  GLint dstY,
272                                                  GLint dstZ,
273                                                  GLsizei srcWidth,
274                                                  GLsizei srcHeight,
275                                                  GLsizei srcDepth)
276 {
277     ContextVk *contextVk = vk::GetImpl(context);
278     TextureVk *sourceVk  = vk::GetImpl(srcTexture);
279 
280     // Make sure the source/destination targets are initialized and all staged updates are flushed.
281     ANGLE_TRY(sourceVk->ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
282     ANGLE_TRY(ensureImageInitialized(context));
283 
284     return vk::ImageHelper::CopyImageSubData(context, &sourceVk->getImage(), srcLevel, srcX, srcY,
285                                              srcZ, mImage, dstLevel, dstX, dstY, dstZ, srcWidth,
286                                              srcHeight, srcDepth);
287 }
288 
getAttachmentRenderTarget(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex,GLsizei samples,FramebufferAttachmentRenderTarget ** rtOut)289 angle::Result RenderbufferVk::getAttachmentRenderTarget(const gl::Context *context,
290                                                         GLenum binding,
291                                                         const gl::ImageIndex &imageIndex,
292                                                         GLsizei samples,
293                                                         FramebufferAttachmentRenderTarget **rtOut)
294 {
295     ASSERT(mImage && mImage->valid());
296     *rtOut = &mRenderTarget;
297     return angle::Result::Continue;
298 }
299 
initializeContents(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex)300 angle::Result RenderbufferVk::initializeContents(const gl::Context *context,
301                                                  GLenum binding,
302                                                  const gl::ImageIndex &imageIndex)
303 {
304     // Note: stageSubresourceRobustClear only uses the intended format to count channels.
305     mImage->stageRobustResourceClear(imageIndex);
306     return mImage->flushAllStagedUpdates(vk::GetImpl(context));
307 }
308 
releaseOwnershipOfImage(const gl::Context * context)309 void RenderbufferVk::releaseOwnershipOfImage(const gl::Context *context)
310 {
311     ContextVk *contextVk = vk::GetImpl(context);
312 
313     ASSERT(!mImageSiblingSerial.valid());
314 
315     mOwnsImage = false;
316     releaseAndDeleteImage(contextVk);
317 }
318 
releaseAndDeleteImage(ContextVk * contextVk)319 void RenderbufferVk::releaseAndDeleteImage(ContextVk *contextVk)
320 {
321     releaseImage(contextVk);
322     SafeDelete(mImage);
323     mImageObserverBinding.bind(nullptr);
324 }
325 
releaseImage(ContextVk * contextVk)326 void RenderbufferVk::releaseImage(ContextVk *contextVk)
327 {
328     vk::Renderer *renderer = contextVk->getRenderer();
329     if (mImage == nullptr)
330     {
331         ASSERT(mImageViews.isImageViewGarbageEmpty() &&
332                mMultisampledImageViews.isImageViewGarbageEmpty());
333     }
334     else
335     {
336         mRenderTarget.releaseImageAndViews(contextVk);
337         mImageViews.release(renderer, mImage->getResourceUse());
338         mMultisampledImageViews.release(renderer, mImage->getResourceUse());
339     }
340 
341     if (mImage && mOwnsImage)
342     {
343         mImage->releaseImageFromShareContexts(renderer, contextVk, mImageSiblingSerial);
344         mImage->releaseStagedUpdates(renderer);
345     }
346     else
347     {
348         if (mImage)
349         {
350             mImage->finalizeImageLayoutInShareContexts(renderer, contextVk, mImageSiblingSerial);
351         }
352         mImage = nullptr;
353         mImageObserverBinding.bind(nullptr);
354     }
355 
356     if (mMultisampledImage.valid())
357     {
358         mMultisampledImage.releaseImageFromShareContexts(renderer, contextVk, mImageSiblingSerial);
359     }
360 }
361 
getImplementationSizedFormat() const362 const gl::InternalFormat &RenderbufferVk::getImplementationSizedFormat() const
363 {
364     GLenum internalFormat = mImage->getActualFormat().glInternalFormat;
365     return gl::GetSizedInternalFormatInfo(internalFormat);
366 }
367 
getColorReadFormat(const gl::Context * context)368 GLenum RenderbufferVk::getColorReadFormat(const gl::Context *context)
369 {
370     const gl::InternalFormat &sizedFormat = getImplementationSizedFormat();
371     return sizedFormat.format;
372 }
373 
getColorReadType(const gl::Context * context)374 GLenum RenderbufferVk::getColorReadType(const gl::Context *context)
375 {
376     const gl::InternalFormat &sizedFormat = getImplementationSizedFormat();
377     return sizedFormat.type;
378 }
379 
getRenderbufferImage(const gl::Context * context,const gl::PixelPackState & packState,gl::Buffer * packBuffer,GLenum format,GLenum type,void * pixels)380 angle::Result RenderbufferVk::getRenderbufferImage(const gl::Context *context,
381                                                    const gl::PixelPackState &packState,
382                                                    gl::Buffer *packBuffer,
383                                                    GLenum format,
384                                                    GLenum type,
385                                                    void *pixels)
386 {
387     // Storage not defined.
388     if (!mImage || !mImage->valid())
389     {
390         return angle::Result::Continue;
391     }
392 
393     ContextVk *contextVk = vk::GetImpl(context);
394     ANGLE_TRY(mImage->flushAllStagedUpdates(contextVk));
395 
396     gl::MaybeOverrideLuminance(format, type, getColorReadFormat(context),
397                                getColorReadType(context));
398 
399     return mImage->readPixelsForGetImage(contextVk, packState, packBuffer, gl::LevelIndex(0), 0, 0,
400                                          format, type, pixels);
401 }
402 
ensureImageInitialized(const gl::Context * context)403 angle::Result RenderbufferVk::ensureImageInitialized(const gl::Context *context)
404 {
405     ANGLE_TRY(setStorage(context, mState.getFormat().info->internalFormat, mState.getWidth(),
406                          mState.getHeight()));
407 
408     return mImage->flushAllStagedUpdates(vk::GetImpl(context));
409 }
410 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)411 void RenderbufferVk::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
412 {
413     ASSERT(index == kRenderbufferImageSubjectIndex &&
414            (message == angle::SubjectMessage::SubjectChanged ||
415             message == angle::SubjectMessage::InitializationComplete));
416 
417     // Forward the notification to the parent class that the staging buffer changed.
418     if (message == angle::SubjectMessage::SubjectChanged)
419     {
420         onStateChange(angle::SubjectMessage::SubjectChanged);
421     }
422 }
423 }  // namespace rx
424