1 // Copyright 2018 The Amber Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/vulkan/frame_buffer.h"
16
17 #include <algorithm>
18 #include <cstring>
19 #include <limits>
20 #include <vector>
21
22 #include "src/make_unique.h"
23 #include "src/vulkan/command_buffer.h"
24 #include "src/vulkan/device.h"
25
26 namespace amber {
27 namespace vulkan {
28
FrameBuffer(Device * device,const std::vector<const amber::Pipeline::BufferInfo * > & color_attachments,amber::Pipeline::BufferInfo depth_stencil_attachment,const std::vector<const amber::Pipeline::BufferInfo * > & resolve_targets,uint32_t width,uint32_t height)29 FrameBuffer::FrameBuffer(
30 Device* device,
31 const std::vector<const amber::Pipeline::BufferInfo*>& color_attachments,
32 amber::Pipeline::BufferInfo depth_stencil_attachment,
33 const std::vector<const amber::Pipeline::BufferInfo*>& resolve_targets,
34 uint32_t width,
35 uint32_t height)
36 : device_(device),
37 color_attachments_(color_attachments),
38 resolve_targets_(resolve_targets),
39 depth_stencil_attachment_(depth_stencil_attachment),
40 width_(width),
41 height_(height) {}
42
~FrameBuffer()43 FrameBuffer::~FrameBuffer() {
44 if (frame_ != VK_NULL_HANDLE) {
45 device_->GetPtrs()->vkDestroyFramebuffer(device_->GetVkDevice(), frame_,
46 nullptr);
47 }
48 }
49
Initialize(VkRenderPass render_pass)50 Result FrameBuffer::Initialize(VkRenderPass render_pass) {
51 std::vector<VkImageView> attachments;
52
53 if (!color_attachments_.empty()) {
54 std::vector<int32_t> seen_idx(color_attachments_.size(), -1);
55 for (auto* info : color_attachments_) {
56 if (info->location >= color_attachments_.size())
57 return Result("color attachment locations must be sequential from 0");
58 if (seen_idx[info->location] != -1) {
59 return Result("duplicate attachment location: " +
60 std::to_string(info->location));
61 }
62 seen_idx[info->location] = static_cast<int32_t>(info->location);
63 }
64
65 attachments.resize(color_attachments_.size());
66 for (auto* info : color_attachments_) {
67 const VkImageUsageFlags usage_flags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
68 VK_IMAGE_USAGE_TRANSFER_DST_BIT |
69 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
70 color_images_.push_back(MakeUnique<TransferImage>(
71 device_, *info->buffer->GetFormat(), VK_IMAGE_ASPECT_COLOR_BIT,
72 VK_IMAGE_TYPE_2D, usage_flags, width_ << info->base_mip_level,
73 height_ << info->base_mip_level, depth_, info->buffer->GetMipLevels(),
74 info->base_mip_level, 1u, info->buffer->GetSamples()));
75
76 Result r = color_images_.back()->Initialize();
77 if (!r.IsSuccess())
78 return r;
79
80 attachments[info->location] = color_images_.back()->GetVkImageView();
81 }
82 }
83
84 if (depth_stencil_attachment_.buffer &&
85 depth_stencil_attachment_.buffer->GetFormat()->IsFormatKnown()) {
86 VkImageAspectFlags aspect = 0;
87 if (depth_stencil_attachment_.buffer->GetFormat()->HasDepthComponent())
88 aspect |= VK_IMAGE_ASPECT_DEPTH_BIT;
89 if (depth_stencil_attachment_.buffer->GetFormat()->HasStencilComponent())
90 aspect |= VK_IMAGE_ASPECT_STENCIL_BIT;
91 assert(aspect != 0);
92
93 const VkImageUsageFlags usage_flags =
94 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
95 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
96
97 depth_stencil_image_ = MakeUnique<TransferImage>(
98 device_, *depth_stencil_attachment_.buffer->GetFormat(), aspect,
99 VK_IMAGE_TYPE_2D, usage_flags, width_, height_, depth_, 1u, 0u, 1u, 1u);
100
101 Result r = depth_stencil_image_->Initialize();
102 if (!r.IsSuccess())
103 return r;
104
105 attachments.push_back(depth_stencil_image_->GetVkImageView());
106 }
107
108 for (auto* info : resolve_targets_) {
109 const VkImageUsageFlags usage_flags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
110 VK_IMAGE_USAGE_TRANSFER_DST_BIT |
111 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
112 resolve_images_.push_back(MakeUnique<TransferImage>(
113 device_, *info->buffer->GetFormat(), VK_IMAGE_ASPECT_COLOR_BIT,
114 VK_IMAGE_TYPE_2D, usage_flags, width_, height_, depth_, 1u, 0u, 1u,
115 1u));
116
117 Result r = resolve_images_.back()->Initialize();
118 if (!r.IsSuccess())
119 return r;
120
121 attachments.push_back(resolve_images_.back()->GetVkImageView());
122 }
123
124 VkFramebufferCreateInfo frame_buffer_info = VkFramebufferCreateInfo();
125 frame_buffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
126 frame_buffer_info.renderPass = render_pass;
127 frame_buffer_info.attachmentCount = static_cast<uint32_t>(attachments.size());
128 frame_buffer_info.pAttachments = attachments.data();
129 frame_buffer_info.width = width_;
130 frame_buffer_info.height = height_;
131 frame_buffer_info.layers = 1;
132
133 if (device_->GetPtrs()->vkCreateFramebuffer(device_->GetVkDevice(),
134 &frame_buffer_info, nullptr,
135 &frame_) != VK_SUCCESS) {
136 return Result("Vulkan::Calling vkCreateFramebuffer Fail");
137 }
138
139 return {};
140 }
141
ChangeFrameLayout(CommandBuffer * command,VkImageLayout color_layout,VkPipelineStageFlags color_stage,VkImageLayout depth_layout,VkPipelineStageFlags depth_stage)142 void FrameBuffer::ChangeFrameLayout(CommandBuffer* command,
143 VkImageLayout color_layout,
144 VkPipelineStageFlags color_stage,
145 VkImageLayout depth_layout,
146 VkPipelineStageFlags depth_stage) {
147 for (auto& img : color_images_)
148 img->ImageBarrier(command, color_layout, color_stage);
149
150 for (auto& img : resolve_images_)
151 img->ImageBarrier(command, color_layout, color_stage);
152
153 if (depth_stencil_image_)
154 depth_stencil_image_->ImageBarrier(command, depth_layout, depth_stage);
155 }
156
ChangeFrameToDrawLayout(CommandBuffer * command)157 void FrameBuffer::ChangeFrameToDrawLayout(CommandBuffer* command) {
158 ChangeFrameLayout(command,
159 // Color attachments
160 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
161 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
162 // Depth attachment
163 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
164 VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
165 }
166
ChangeFrameToProbeLayout(CommandBuffer * command)167 void FrameBuffer::ChangeFrameToProbeLayout(CommandBuffer* command) {
168 ChangeFrameLayout(
169 command,
170 // Color attachments
171 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT,
172 // Depth attachments
173 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT);
174 }
175
ChangeFrameToWriteLayout(CommandBuffer * command)176 void FrameBuffer::ChangeFrameToWriteLayout(CommandBuffer* command) {
177 ChangeFrameLayout(
178 command,
179 // Color attachments
180 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT,
181 // Depth attachments
182 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT);
183 }
184
TransferImagesToHost(CommandBuffer * command)185 void FrameBuffer::TransferImagesToHost(CommandBuffer* command) {
186 for (auto& img : color_images_)
187 img->CopyToHost(command);
188
189 for (auto& img : resolve_images_)
190 img->CopyToHost(command);
191
192 if (depth_stencil_image_)
193 depth_stencil_image_->CopyToHost(command);
194 }
195
CopyImagesToBuffers()196 void FrameBuffer::CopyImagesToBuffers() {
197 for (size_t i = 0; i < color_images_.size(); ++i) {
198 auto& img = color_images_[i];
199 auto* info = color_attachments_[i];
200 auto* values = info->buffer->ValuePtr();
201 values->resize(info->buffer->GetSizeInBytes());
202 std::memcpy(values->data(), img->HostAccessibleMemoryPtr(),
203 info->buffer->GetSizeInBytes());
204 }
205
206 for (size_t i = 0; i < resolve_images_.size(); ++i) {
207 auto& img = resolve_images_[i];
208 auto* info = resolve_targets_[i];
209 auto* values = info->buffer->ValuePtr();
210 values->resize(info->buffer->GetSizeInBytes());
211 std::memcpy(values->data(), img->HostAccessibleMemoryPtr(),
212 info->buffer->GetSizeInBytes());
213 }
214
215 if (depth_stencil_image_) {
216 auto* values = depth_stencil_attachment_.buffer->ValuePtr();
217 values->resize(depth_stencil_attachment_.buffer->GetSizeInBytes());
218 std::memcpy(values->data(), depth_stencil_image_->HostAccessibleMemoryPtr(),
219 depth_stencil_attachment_.buffer->GetSizeInBytes());
220 }
221 }
222
TransferImagesToDevice(CommandBuffer * command)223 void FrameBuffer::TransferImagesToDevice(CommandBuffer* command) {
224 for (auto& img : color_images_)
225 img->CopyToDevice(command);
226
227 if (depth_stencil_image_)
228 depth_stencil_image_->CopyToDevice(command);
229 }
230
CopyBuffersToImages()231 void FrameBuffer::CopyBuffersToImages() {
232 for (size_t i = 0; i < color_images_.size(); ++i) {
233 auto& img = color_images_[i];
234 auto* info = color_attachments_[i];
235 auto* values = info->buffer->ValuePtr();
236 // Nothing to do if our local buffer is empty
237 if (values->empty())
238 continue;
239
240 std::memcpy(img->HostAccessibleMemoryPtr(), values->data(),
241 info->buffer->GetSizeInBytes());
242 }
243
244 for (size_t i = 0; i < resolve_images_.size(); ++i) {
245 auto& img = resolve_images_[i];
246 auto* info = resolve_targets_[i];
247 auto* values = info->buffer->ValuePtr();
248 // Nothing to do if our local buffer is empty
249 if (values->empty())
250 continue;
251
252 std::memcpy(img->HostAccessibleMemoryPtr(), values->data(),
253 info->buffer->GetSizeInBytes());
254 }
255
256 if (depth_stencil_image_) {
257 auto* values = depth_stencil_attachment_.buffer->ValuePtr();
258 // Nothing to do if our local buffer is empty
259 if (!values->empty()) {
260 std::memcpy(depth_stencil_image_->HostAccessibleMemoryPtr(),
261 values->data(),
262 depth_stencil_attachment_.buffer->GetSizeInBytes());
263 }
264 }
265 }
266
267 } // namespace vulkan
268 } // namespace amber
269