• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/RendererVk.h"
17 #include "libANGLE/renderer/vulkan/TextureVk.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     RendererVk *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         mImageObserverBinding.bind(mImage);
79         mImageViews.init(renderer);
80     }
81 
82     const angle::Format &textureFormat = format.getActualRenderableImageFormat();
83     const bool isDepthStencilFormat    = textureFormat.hasDepthOrStencilBits();
84     ASSERT(textureFormat.redBits > 0 || isDepthStencilFormat);
85 
86     const bool isRenderToTexture = mode == gl::MultisamplingMode::MultisampledRenderToTexture;
87     const bool hasRenderToTextureEXT =
88         renderer->getFeatures().supportsMultisampledRenderToSingleSampled.enabled;
89 
90     // Transfer and sampled usage are used for various utilities such as readback or blit.
91     VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
92                               VK_IMAGE_USAGE_SAMPLED_BIT;
93 
94     // Renderbuffer's normal usage is as framebuffer attachment.
95     usage |= isDepthStencilFormat ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
96                                   : VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
97 
98     // When used to emulate multisampled render to texture, it can be read as input attachment.
99     if (isRenderToTexture && !hasRenderToTextureEXT)
100     {
101         usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
102     }
103 
104     // For framebuffer fetch and advanced blend emulation, color will be read as input attachment.
105     if (!isDepthStencilFormat)
106     {
107         usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
108     }
109 
110     const uint32_t imageSamples = isRenderToTexture ? 1 : samples;
111 
112     bool robustInit = contextVk->isRobustResourceInitEnabled();
113 
114     VkExtent3D extents = {static_cast<uint32_t>(width), static_cast<uint32_t>(height), 1u};
115     ANGLE_TRY(mImage->initExternal(contextVk, gl::TextureType::_2D, extents,
116                                    format.getIntendedFormatID(), textureFormatID, imageSamples,
117                                    usage, vk::kVkImageCreateFlagsNone, vk::ImageLayout::Undefined,
118                                    nullptr, gl::LevelIndex(0), 1, 1, robustInit, false));
119 
120     VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
121     ANGLE_TRY(mImage->initMemory(contextVk, false, renderer->getMemoryProperties(), flags));
122 
123     // If multisampled render to texture, an implicit multisampled image is created which is used as
124     // the color or depth/stencil attachment.  At the end of the render pass, this image is
125     // automatically resolved into |mImage| and its contents are discarded.
126     if (isRenderToTexture && !hasRenderToTextureEXT)
127     {
128         mMultisampledImageViews.init(renderer);
129 
130         ANGLE_TRY(mMultisampledImage.initImplicitMultisampledRenderToTexture(
131             contextVk, false, renderer->getMemoryProperties(), gl::TextureType::_2D, samples,
132             *mImage, robustInit));
133 
134         mRenderTarget.init(&mMultisampledImage, &mMultisampledImageViews, mImage, &mImageViews,
135                            gl::LevelIndex(0), 0, 1, RenderTargetTransience::MultisampledTransient);
136     }
137     else
138     {
139         mRenderTarget.init(mImage, &mImageViews, nullptr, nullptr, gl::LevelIndex(0), 0, 1,
140                            RenderTargetTransience::Default);
141     }
142 
143     return angle::Result::Continue;
144 }
145 
setStorage(const gl::Context * context,GLenum internalformat,GLsizei width,GLsizei height)146 angle::Result RenderbufferVk::setStorage(const gl::Context *context,
147                                          GLenum internalformat,
148                                          GLsizei width,
149                                          GLsizei height)
150 {
151     // The ES 3.0 spec(section 4.4.2.1) states that RenderbufferStorage is equivalent to calling
152     // RenderbufferStorageMultisample with samples equal to zero.
153     return setStorageImpl(context, 0, internalformat, width, height,
154                           gl::MultisamplingMode::Regular);
155 }
156 
setStorageMultisample(const gl::Context * context,GLsizei samples,GLenum internalformat,GLsizei width,GLsizei height,gl::MultisamplingMode mode)157 angle::Result RenderbufferVk::setStorageMultisample(const gl::Context *context,
158                                                     GLsizei samples,
159                                                     GLenum internalformat,
160                                                     GLsizei width,
161                                                     GLsizei height,
162                                                     gl::MultisamplingMode mode)
163 {
164     return setStorageImpl(context, samples, internalformat, width, height, mode);
165 }
166 
setStorageEGLImageTarget(const gl::Context * context,egl::Image * image)167 angle::Result RenderbufferVk::setStorageEGLImageTarget(const gl::Context *context,
168                                                        egl::Image *image)
169 {
170     ContextVk *contextVk = vk::GetImpl(context);
171     RendererVk *renderer = contextVk->getRenderer();
172 
173     releaseAndDeleteImage(contextVk);
174 
175     ImageVk *imageVk = vk::GetImpl(image);
176     mImage           = imageVk->getImage();
177     mOwnsImage       = false;
178     mImageObserverBinding.bind(mImage);
179     mImageViews.init(renderer);
180 
181     const vk::Format &vkFormat = renderer->getFormat(image->getFormat().info->sizedInternalFormat);
182     const angle::Format &textureFormat = vkFormat.getActualRenderableImageFormat();
183 
184     VkImageAspectFlags aspect = vk::GetFormatAspectFlags(textureFormat);
185 
186     // Transfer the image to this queue if needed
187     uint32_t rendererQueueFamilyIndex = contextVk->getRenderer()->getQueueFamilyIndex();
188     if (mImage->isQueueChangeNeccesary(rendererQueueFamilyIndex))
189     {
190         vk::OutsideRenderPassCommandBuffer *commandBuffer;
191         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &commandBuffer));
192         mImage->retain(&contextVk->getResourceUseList());
193         mImage->changeLayoutAndQueue(contextVk, aspect, vk::ImageLayout::ColorAttachment,
194                                      rendererQueueFamilyIndex, commandBuffer);
195     }
196 
197     mRenderTarget.init(mImage, &mImageViews, nullptr, nullptr, imageVk->getImageLevel(),
198                        imageVk->getImageLayer(), 1, RenderTargetTransience::Default);
199 
200     return angle::Result::Continue;
201 }
202 
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)203 angle::Result RenderbufferVk::copyRenderbufferSubData(const gl::Context *context,
204                                                       const gl::Renderbuffer *srcBuffer,
205                                                       GLint srcLevel,
206                                                       GLint srcX,
207                                                       GLint srcY,
208                                                       GLint srcZ,
209                                                       GLint dstLevel,
210                                                       GLint dstX,
211                                                       GLint dstY,
212                                                       GLint dstZ,
213                                                       GLsizei srcWidth,
214                                                       GLsizei srcHeight,
215                                                       GLsizei srcDepth)
216 {
217     RenderbufferVk *sourceVk = vk::GetImpl(srcBuffer);
218 
219     // Make sure the source/destination targets are initialized and all staged updates are flushed.
220     ANGLE_TRY(sourceVk->ensureImageInitialized(context));
221     ANGLE_TRY(ensureImageInitialized(context));
222 
223     return vk::ImageHelper::CopyImageSubData(context, sourceVk->getImage(), srcLevel, srcX, srcY,
224                                              srcZ, mImage, dstLevel, dstX, dstY, dstZ, srcWidth,
225                                              srcHeight, srcDepth);
226 }
227 
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)228 angle::Result RenderbufferVk::copyTextureSubData(const gl::Context *context,
229                                                  const gl::Texture *srcTexture,
230                                                  GLint srcLevel,
231                                                  GLint srcX,
232                                                  GLint srcY,
233                                                  GLint srcZ,
234                                                  GLint dstLevel,
235                                                  GLint dstX,
236                                                  GLint dstY,
237                                                  GLint dstZ,
238                                                  GLsizei srcWidth,
239                                                  GLsizei srcHeight,
240                                                  GLsizei srcDepth)
241 {
242     ContextVk *contextVk = vk::GetImpl(context);
243     TextureVk *sourceVk  = vk::GetImpl(srcTexture);
244 
245     // Make sure the source/destination targets are initialized and all staged updates are flushed.
246     ANGLE_TRY(sourceVk->ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
247     ANGLE_TRY(ensureImageInitialized(context));
248 
249     return vk::ImageHelper::CopyImageSubData(context, &sourceVk->getImage(), srcLevel, srcX, srcY,
250                                              srcZ, mImage, dstLevel, dstX, dstY, dstZ, srcWidth,
251                                              srcHeight, srcDepth);
252 }
253 
getAttachmentRenderTarget(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex,GLsizei samples,FramebufferAttachmentRenderTarget ** rtOut)254 angle::Result RenderbufferVk::getAttachmentRenderTarget(const gl::Context *context,
255                                                         GLenum binding,
256                                                         const gl::ImageIndex &imageIndex,
257                                                         GLsizei samples,
258                                                         FramebufferAttachmentRenderTarget **rtOut)
259 {
260     ASSERT(mImage && mImage->valid());
261     *rtOut = &mRenderTarget;
262     return angle::Result::Continue;
263 }
264 
initializeContents(const gl::Context * context,const gl::ImageIndex & imageIndex)265 angle::Result RenderbufferVk::initializeContents(const gl::Context *context,
266                                                  const gl::ImageIndex &imageIndex)
267 {
268     // Note: stageSubresourceRobustClear only uses the intended format to count channels.
269     mImage->stageRobustResourceClear(imageIndex);
270     return mImage->flushAllStagedUpdates(vk::GetImpl(context));
271 }
272 
releaseOwnershipOfImage(const gl::Context * context)273 void RenderbufferVk::releaseOwnershipOfImage(const gl::Context *context)
274 {
275     ContextVk *contextVk = vk::GetImpl(context);
276 
277     mOwnsImage = false;
278     releaseAndDeleteImage(contextVk);
279 }
280 
releaseAndDeleteImage(ContextVk * contextVk)281 void RenderbufferVk::releaseAndDeleteImage(ContextVk *contextVk)
282 {
283     releaseImage(contextVk);
284     SafeDelete(mImage);
285     mImageObserverBinding.bind(nullptr);
286 }
287 
releaseImage(ContextVk * contextVk)288 void RenderbufferVk::releaseImage(ContextVk *contextVk)
289 {
290     RendererVk *renderer = contextVk->getRenderer();
291     if (mImage == nullptr)
292     {
293         ASSERT(mImageViews.isImageViewGarbageEmpty() &&
294                mMultisampledImageViews.isImageViewGarbageEmpty());
295     }
296     else
297     {
298         mImage->collectViewGarbage(renderer, &mImageViews);
299         mImage->collectViewGarbage(renderer, &mMultisampledImageViews);
300     }
301 
302     if (mImage && mOwnsImage)
303     {
304         mImage->releaseImageFromShareContexts(renderer, contextVk);
305         mImage->releaseStagedUpdates(renderer);
306     }
307     else
308     {
309         mImage = nullptr;
310         mImageObserverBinding.bind(nullptr);
311     }
312 
313     if (mMultisampledImage.valid())
314     {
315         mMultisampledImage.releaseImageFromShareContexts(renderer, contextVk);
316     }
317 }
318 
getImplementationSizedFormat() const319 const gl::InternalFormat &RenderbufferVk::getImplementationSizedFormat() const
320 {
321     GLenum internalFormat = mImage->getActualFormat().glInternalFormat;
322     return gl::GetSizedInternalFormatInfo(internalFormat);
323 }
324 
getColorReadFormat(const gl::Context * context)325 GLenum RenderbufferVk::getColorReadFormat(const gl::Context *context)
326 {
327     const gl::InternalFormat &sizedFormat = getImplementationSizedFormat();
328     return sizedFormat.format;
329 }
330 
getColorReadType(const gl::Context * context)331 GLenum RenderbufferVk::getColorReadType(const gl::Context *context)
332 {
333     const gl::InternalFormat &sizedFormat = getImplementationSizedFormat();
334     return sizedFormat.type;
335 }
336 
getRenderbufferImage(const gl::Context * context,const gl::PixelPackState & packState,gl::Buffer * packBuffer,GLenum format,GLenum type,void * pixels)337 angle::Result RenderbufferVk::getRenderbufferImage(const gl::Context *context,
338                                                    const gl::PixelPackState &packState,
339                                                    gl::Buffer *packBuffer,
340                                                    GLenum format,
341                                                    GLenum type,
342                                                    void *pixels)
343 {
344     // Storage not defined.
345     if (!mImage || !mImage->valid())
346     {
347         return angle::Result::Continue;
348     }
349 
350     ContextVk *contextVk = vk::GetImpl(context);
351     ANGLE_TRY(mImage->flushAllStagedUpdates(contextVk));
352 
353     gl::MaybeOverrideLuminance(format, type, getColorReadFormat(context),
354                                getColorReadType(context));
355 
356     return mImage->readPixelsForGetImage(contextVk, packState, packBuffer, gl::LevelIndex(0), 0, 0,
357                                          format, type, pixels);
358 }
359 
ensureImageInitialized(const gl::Context * context)360 angle::Result RenderbufferVk::ensureImageInitialized(const gl::Context *context)
361 {
362     ANGLE_TRY(setStorage(context, mState.getFormat().info->internalFormat, mState.getWidth(),
363                          mState.getHeight()));
364 
365     return mImage->flushAllStagedUpdates(vk::GetImpl(context));
366 }
367 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)368 void RenderbufferVk::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
369 {
370     ASSERT(index == kRenderbufferImageSubjectIndex &&
371            (message == angle::SubjectMessage::SubjectChanged ||
372             message == angle::SubjectMessage::InitializationComplete));
373 
374     // Forward the notification to the parent class that the staging buffer changed.
375     if (message == angle::SubjectMessage::SubjectChanged)
376     {
377         onStateChange(angle::SubjectMessage::SubjectChanged);
378     }
379 }
380 }  // namespace rx
381