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