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