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