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,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 uint32_t width,
34 uint32_t height)
35 : device_(device),
36 color_attachments_(color_attachments),
37 depth_stencil_attachment_(depth_stencil_attachment),
38 width_(width),
39 height_(height) {}
40
~FrameBuffer()41 FrameBuffer::~FrameBuffer() {
42 if (frame_ != VK_NULL_HANDLE) {
43 device_->GetPtrs()->vkDestroyFramebuffer(device_->GetVkDevice(), frame_,
44 nullptr);
45 }
46 }
47
Initialize(VkRenderPass render_pass)48 Result FrameBuffer::Initialize(VkRenderPass render_pass) {
49 std::vector<VkImageView> attachments;
50
51 if (!color_attachments_.empty()) {
52 std::vector<int32_t> seen_idx(color_attachments_.size(), -1);
53 for (auto* info : color_attachments_) {
54 if (info->location >= color_attachments_.size())
55 return Result("color attachment locations must be sequential from 0");
56 if (seen_idx[info->location] != -1) {
57 return Result("duplicate attachment location: " +
58 std::to_string(info->location));
59 }
60 seen_idx[info->location] = static_cast<int32_t>(info->location);
61 }
62
63 attachments.resize(color_attachments_.size());
64 for (auto* info : color_attachments_) {
65 color_images_.push_back(MakeUnique<TransferImage>(
66 device_, *info->buffer->GetFormat(), VK_IMAGE_ASPECT_COLOR_BIT,
67 VK_IMAGE_TYPE_2D, width_ << info->base_mip_level,
68 height_ << info->base_mip_level, depth_, info->buffer->GetMipLevels(),
69 info->base_mip_level, 1u, 1u));
70
71 Result r = color_images_.back()->Initialize(
72 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
73 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
74 if (!r.IsSuccess())
75 return r;
76
77 attachments[info->location] = color_images_.back()->GetVkImageView();
78 }
79 }
80
81 if (depth_stencil_attachment_.buffer &&
82 depth_stencil_attachment_.buffer->GetFormat()->IsFormatKnown()) {
83 VkImageAspectFlags aspect = 0;
84 if (depth_stencil_attachment_.buffer->GetFormat()->HasDepthComponent())
85 aspect |= VK_IMAGE_ASPECT_DEPTH_BIT;
86 if (depth_stencil_attachment_.buffer->GetFormat()->HasStencilComponent())
87 aspect |= VK_IMAGE_ASPECT_STENCIL_BIT;
88 assert(aspect != 0);
89
90 depth_stencil_image_ = MakeUnique<TransferImage>(
91 device_, *depth_stencil_attachment_.buffer->GetFormat(), aspect,
92 VK_IMAGE_TYPE_2D, width_, height_, depth_, 1u, 0u, 1u, 1u);
93
94 Result r = depth_stencil_image_->Initialize(
95 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
96 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
97 if (!r.IsSuccess())
98 return r;
99
100 attachments.push_back(depth_stencil_image_->GetVkImageView());
101 }
102
103 VkFramebufferCreateInfo frame_buffer_info = VkFramebufferCreateInfo();
104 frame_buffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
105 frame_buffer_info.renderPass = render_pass;
106 frame_buffer_info.attachmentCount = static_cast<uint32_t>(attachments.size());
107 frame_buffer_info.pAttachments = attachments.data();
108 frame_buffer_info.width = width_;
109 frame_buffer_info.height = height_;
110 frame_buffer_info.layers = 1;
111
112 if (device_->GetPtrs()->vkCreateFramebuffer(device_->GetVkDevice(),
113 &frame_buffer_info, nullptr,
114 &frame_) != VK_SUCCESS) {
115 return Result("Vulkan::Calling vkCreateFramebuffer Fail");
116 }
117
118 return {};
119 }
120
ChangeFrameLayout(CommandBuffer * command,VkImageLayout color_layout,VkPipelineStageFlags color_stage,VkImageLayout depth_layout,VkPipelineStageFlags depth_stage)121 void FrameBuffer::ChangeFrameLayout(CommandBuffer* command,
122 VkImageLayout color_layout,
123 VkPipelineStageFlags color_stage,
124 VkImageLayout depth_layout,
125 VkPipelineStageFlags depth_stage) {
126 for (auto& img : color_images_)
127 img->ImageBarrier(command, color_layout, color_stage);
128
129 if (depth_stencil_image_)
130 depth_stencil_image_->ImageBarrier(command, depth_layout, depth_stage);
131 }
132
ChangeFrameToDrawLayout(CommandBuffer * command)133 void FrameBuffer::ChangeFrameToDrawLayout(CommandBuffer* command) {
134 ChangeFrameLayout(command,
135 // Color attachments
136 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
137 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
138 // Depth attachment
139 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
140 VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
141 }
142
ChangeFrameToProbeLayout(CommandBuffer * command)143 void FrameBuffer::ChangeFrameToProbeLayout(CommandBuffer* command) {
144 ChangeFrameLayout(
145 command,
146 // Color attachments
147 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT,
148 // Depth attachments
149 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT);
150 }
151
ChangeFrameToWriteLayout(CommandBuffer * command)152 void FrameBuffer::ChangeFrameToWriteLayout(CommandBuffer* command) {
153 ChangeFrameLayout(
154 command,
155 // Color attachments
156 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT,
157 // Depth attachments
158 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT);
159 }
160
TransferImagesToHost(CommandBuffer * command)161 void FrameBuffer::TransferImagesToHost(CommandBuffer* command) {
162 for (auto& img : color_images_)
163 img->CopyToHost(command);
164
165 if (depth_stencil_image_)
166 depth_stencil_image_->CopyToHost(command);
167 }
168
CopyImagesToBuffers()169 void FrameBuffer::CopyImagesToBuffers() {
170 for (size_t i = 0; i < color_images_.size(); ++i) {
171 auto& img = color_images_[i];
172 auto* info = color_attachments_[i];
173 auto* values = info->buffer->ValuePtr();
174 values->resize(info->buffer->GetSizeInBytes());
175 std::memcpy(values->data(), img->HostAccessibleMemoryPtr(),
176 info->buffer->GetSizeInBytes());
177 }
178
179 if (depth_stencil_image_) {
180 auto* values = depth_stencil_attachment_.buffer->ValuePtr();
181 values->resize(depth_stencil_attachment_.buffer->GetSizeInBytes());
182 std::memcpy(values->data(), depth_stencil_image_->HostAccessibleMemoryPtr(),
183 depth_stencil_attachment_.buffer->GetSizeInBytes());
184 }
185 }
186
TransferImagesToDevice(CommandBuffer * command)187 void FrameBuffer::TransferImagesToDevice(CommandBuffer* command) {
188 for (auto& img : color_images_)
189 img->CopyToDevice(command);
190
191 if (depth_stencil_image_)
192 depth_stencil_image_->CopyToDevice(command);
193 }
194
CopyBuffersToImages()195 void FrameBuffer::CopyBuffersToImages() {
196 for (size_t i = 0; i < color_images_.size(); ++i) {
197 auto& img = color_images_[i];
198 auto* info = color_attachments_[i];
199 auto* values = info->buffer->ValuePtr();
200 // Nothing to do if our local buffer is empty
201 if (values->empty())
202 continue;
203
204 std::memcpy(img->HostAccessibleMemoryPtr(), values->data(),
205 info->buffer->GetSizeInBytes());
206 }
207
208 if (depth_stencil_image_) {
209 auto* values = depth_stencil_attachment_.buffer->ValuePtr();
210 // Nothing to do if our local buffer is empty
211 if (!values->empty()) {
212 std::memcpy(depth_stencil_image_->HostAccessibleMemoryPtr(),
213 values->data(),
214 depth_stencil_attachment_.buffer->GetSizeInBytes());
215 }
216 }
217 }
218
219 } // namespace vulkan
220 } // namespace amber
221