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