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
18 namespace rx
19 {
20 namespace
21 {
22 angle::SubjectIndex kRenderbufferImageSubjectIndex = 0;
23 } // namespace
24
RenderbufferVk(const gl::RenderbufferState & state)25 RenderbufferVk::RenderbufferVk(const gl::RenderbufferState &state)
26 : RenderbufferImpl(state),
27 mOwnsImage(false),
28 mImage(nullptr),
29 mImageObserverBinding(this, kRenderbufferImageSubjectIndex)
30 {}
31
~RenderbufferVk()32 RenderbufferVk::~RenderbufferVk() {}
33
onDestroy(const gl::Context * context)34 void RenderbufferVk::onDestroy(const gl::Context *context)
35 {
36 ContextVk *contextVk = vk::GetImpl(context);
37 releaseAndDeleteImage(contextVk);
38 }
39
setStorageImpl(const gl::Context * context,size_t samples,GLenum internalformat,size_t width,size_t height)40 angle::Result RenderbufferVk::setStorageImpl(const gl::Context *context,
41 size_t samples,
42 GLenum internalformat,
43 size_t width,
44 size_t height)
45 {
46 ContextVk *contextVk = vk::GetImpl(context);
47 RendererVk *renderer = contextVk->getRenderer();
48 const vk::Format &vkFormat = renderer->getFormat(internalformat);
49
50 if (!mOwnsImage)
51 {
52 releaseAndDeleteImage(contextVk);
53 }
54
55 if (mImage != nullptr && mImage->valid())
56 {
57 // Check against the state if we need to recreate the storage.
58 if (internalformat != mState.getFormat().info->internalFormat ||
59 static_cast<GLsizei>(width) != mState.getWidth() ||
60 static_cast<GLsizei>(height) != mState.getHeight())
61 {
62 releaseImage(contextVk);
63 }
64 }
65
66 if ((mImage == nullptr || !mImage->valid()) && (width != 0 && height != 0))
67 {
68 if (mImage == nullptr)
69 {
70 mImage = new vk::ImageHelper();
71 mOwnsImage = true;
72 mImageObserverBinding.bind(mImage);
73 }
74
75 const angle::Format &textureFormat = vkFormat.actualImageFormat();
76 bool isDepthOrStencilFormat = textureFormat.depthBits > 0 || textureFormat.stencilBits > 0;
77 const VkImageUsageFlags usage =
78 VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
79 VK_IMAGE_USAGE_SAMPLED_BIT |
80 (textureFormat.redBits > 0 ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT : 0) |
81 (isDepthOrStencilFormat ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT : 0);
82
83 VkExtent3D extents = {static_cast<uint32_t>(width), static_cast<uint32_t>(height), 1u};
84 ANGLE_TRY(mImage->init(contextVk, gl::TextureType::_2D, extents, vkFormat,
85 static_cast<uint32_t>(samples), usage, 0, 0, 1, 1));
86
87 VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
88 ANGLE_TRY(mImage->initMemory(contextVk, renderer->getMemoryProperties(), flags));
89
90 mRenderTarget.init(mImage, &mImageViews, 0, 0);
91 }
92
93 return angle::Result::Continue;
94 }
95
setStorage(const gl::Context * context,GLenum internalformat,size_t width,size_t height)96 angle::Result RenderbufferVk::setStorage(const gl::Context *context,
97 GLenum internalformat,
98 size_t width,
99 size_t height)
100 {
101 return setStorageImpl(context, 1, internalformat, width, height);
102 }
103
setStorageMultisample(const gl::Context * context,size_t samples,GLenum internalformat,size_t width,size_t height)104 angle::Result RenderbufferVk::setStorageMultisample(const gl::Context *context,
105 size_t samples,
106 GLenum internalformat,
107 size_t width,
108 size_t height)
109 {
110 return setStorageImpl(context, samples, internalformat, width, height);
111 }
112
setStorageEGLImageTarget(const gl::Context * context,egl::Image * image)113 angle::Result RenderbufferVk::setStorageEGLImageTarget(const gl::Context *context,
114 egl::Image *image)
115 {
116 ContextVk *contextVk = vk::GetImpl(context);
117 RendererVk *renderer = contextVk->getRenderer();
118
119 releaseAndDeleteImage(contextVk);
120
121 ImageVk *imageVk = vk::GetImpl(image);
122 mImage = imageVk->getImage();
123 mOwnsImage = false;
124 mImageObserverBinding.bind(mImage);
125
126 const vk::Format &vkFormat = renderer->getFormat(image->getFormat().info->sizedInternalFormat);
127 const angle::Format &textureFormat = vkFormat.actualImageFormat();
128
129 VkImageAspectFlags aspect = vk::GetFormatAspectFlags(textureFormat);
130
131 // Transfer the image to this queue if needed
132 uint32_t rendererQueueFamilyIndex = contextVk->getRenderer()->getQueueFamilyIndex();
133 if (mImage->isQueueChangeNeccesary(rendererQueueFamilyIndex))
134 {
135 vk::CommandBuffer *commandBuffer = nullptr;
136 ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
137 mImage->changeLayoutAndQueue(aspect, vk::ImageLayout::ColorAttachment,
138 rendererQueueFamilyIndex, commandBuffer);
139 }
140
141 gl::TextureType viewType = imageVk->getImageTextureType();
142
143 if (imageVk->getImageTextureType() == gl::TextureType::CubeMap)
144 {
145 viewType = vk::Get2DTextureType(imageVk->getImage()->getLayerCount(),
146 imageVk->getImage()->getSamples());
147 }
148
149 mRenderTarget.init(mImage, &mImageViews, imageVk->getImageLevel(), imageVk->getImageLayer());
150
151 return angle::Result::Continue;
152 }
153
getAttachmentRenderTarget(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex,GLsizei samples,FramebufferAttachmentRenderTarget ** rtOut)154 angle::Result RenderbufferVk::getAttachmentRenderTarget(const gl::Context *context,
155 GLenum binding,
156 const gl::ImageIndex &imageIndex,
157 GLsizei samples,
158 FramebufferAttachmentRenderTarget **rtOut)
159 {
160 ASSERT(mImage && mImage->valid());
161 *rtOut = &mRenderTarget;
162 return angle::Result::Continue;
163 }
164
initializeContents(const gl::Context * context,const gl::ImageIndex & imageIndex)165 angle::Result RenderbufferVk::initializeContents(const gl::Context *context,
166 const gl::ImageIndex &imageIndex)
167 {
168 // Note: stageSubresourceRobustClear only uses the intended format to count channels.
169 mImage->stageRobustResourceClear(imageIndex);
170 return mImage->flushAllStagedUpdates(vk::GetImpl(context));
171 }
172
releaseOwnershipOfImage(const gl::Context * context)173 void RenderbufferVk::releaseOwnershipOfImage(const gl::Context *context)
174 {
175 ContextVk *contextVk = vk::GetImpl(context);
176
177 mOwnsImage = false;
178 releaseAndDeleteImage(contextVk);
179 }
180
releaseAndDeleteImage(ContextVk * contextVk)181 void RenderbufferVk::releaseAndDeleteImage(ContextVk *contextVk)
182 {
183 releaseImage(contextVk);
184 SafeDelete(mImage);
185 mImageObserverBinding.bind(nullptr);
186 }
187
releaseImage(ContextVk * contextVk)188 void RenderbufferVk::releaseImage(ContextVk *contextVk)
189 {
190 RendererVk *renderer = contextVk->getRenderer();
191
192 if (mImage && mOwnsImage)
193 {
194 mImage->releaseImage(renderer);
195 mImage->releaseStagingBuffer(renderer);
196 }
197 else
198 {
199 mImage = nullptr;
200 mImageObserverBinding.bind(nullptr);
201 }
202
203 mImageViews.release(renderer);
204 }
205
getImplementationSizedFormat() const206 const gl::InternalFormat &RenderbufferVk::getImplementationSizedFormat() const
207 {
208 GLenum internalFormat = mImage->getFormat().actualImageFormat().glInternalFormat;
209 return gl::GetSizedInternalFormatInfo(internalFormat);
210 }
211
getColorReadFormat(const gl::Context * context)212 GLenum RenderbufferVk::getColorReadFormat(const gl::Context *context)
213 {
214 const gl::InternalFormat &sizedFormat = getImplementationSizedFormat();
215 return sizedFormat.format;
216 }
217
getColorReadType(const gl::Context * context)218 GLenum RenderbufferVk::getColorReadType(const gl::Context *context)
219 {
220 const gl::InternalFormat &sizedFormat = getImplementationSizedFormat();
221 return sizedFormat.type;
222 }
223
getRenderbufferImage(const gl::Context * context,const gl::PixelPackState & packState,gl::Buffer * packBuffer,GLenum format,GLenum type,void * pixels)224 angle::Result RenderbufferVk::getRenderbufferImage(const gl::Context *context,
225 const gl::PixelPackState &packState,
226 gl::Buffer *packBuffer,
227 GLenum format,
228 GLenum type,
229 void *pixels)
230 {
231 // Storage not defined.
232 if (!mImage || !mImage->valid())
233 return angle::Result::Continue;
234
235 ContextVk *contextVk = vk::GetImpl(context);
236 ANGLE_TRY(mImage->flushAllStagedUpdates(contextVk));
237 return mImage->readPixelsForGetImage(contextVk, packState, packBuffer, 0, 0, format, type,
238 pixels);
239 }
240
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)241 void RenderbufferVk::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
242 {
243 ASSERT(index == kRenderbufferImageSubjectIndex &&
244 message == angle::SubjectMessage::SubjectChanged);
245
246 // Forward the notification to the parent class that the staging buffer changed.
247 onStateChange(angle::SubjectMessage::SubjectChanged);
248 }
249 } // namespace rx
250