1 /* Copyright (c) 2017-2018 Hans-Kristian Arntzen
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be
12  * included in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 #include "image.hpp"
24 #include "device.hpp"
25 #include "buffer.hpp"
26 
27 using namespace std;
28 
29 namespace Vulkan
30 {
31 
ImageView(Device * device,VkImageView view,const ImageViewCreateInfo & info)32 ImageView::ImageView(Device *device, VkImageView view, const ImageViewCreateInfo &info)
33     : Cookie(device)
34     , device(device)
35     , view(view)
36     , info(info)
37 {
38 }
39 
get_render_target_view(unsigned layer) const40 VkImageView ImageView::get_render_target_view(unsigned layer) const
41 {
42 	// Transient images just have one layer.
43 	if (info.image->get_create_info().domain == ImageDomain::Transient)
44 		return view;
45 
46 	VK_ASSERT(layer < get_create_info().layers);
47 
48 	if (render_target_views.empty())
49 		return view;
50 	else
51 	{
52 		VK_ASSERT(layer < render_target_views.size());
53 		return render_target_views[layer];
54 	}
55 }
56 
~ImageView()57 ImageView::~ImageView()
58 {
59 	if (internal_sync)
60 	{
61 		device->destroy_image_view_nolock(view);
62 		if (depth_view != VK_NULL_HANDLE)
63 			device->destroy_image_view_nolock(depth_view);
64 		if (stencil_view != VK_NULL_HANDLE)
65 			device->destroy_image_view_nolock(stencil_view);
66 		if (unorm_view != VK_NULL_HANDLE)
67 			device->destroy_image_view_nolock(unorm_view);
68 		if (srgb_view != VK_NULL_HANDLE)
69 			device->destroy_image_view_nolock(srgb_view);
70 
71 		for (auto &view : render_target_views)
72 			device->destroy_image_view_nolock(view);
73 	}
74 	else
75 	{
76 		device->destroy_image_view(view);
77 		if (depth_view != VK_NULL_HANDLE)
78 			device->destroy_image_view(depth_view);
79 		if (stencil_view != VK_NULL_HANDLE)
80 			device->destroy_image_view(stencil_view);
81 		if (unorm_view != VK_NULL_HANDLE)
82 			device->destroy_image_view(unorm_view);
83 		if (srgb_view != VK_NULL_HANDLE)
84 			device->destroy_image_view(srgb_view);
85 
86 		for (auto &view : render_target_views)
87 			device->destroy_image_view(view);
88 	}
89 }
90 
Image(Device * device,VkImage image,VkImageView default_view,const DeviceAllocation & alloc,const ImageCreateInfo & create_info)91 Image::Image(Device *device, VkImage image, VkImageView default_view, const DeviceAllocation &alloc,
92              const ImageCreateInfo &create_info)
93     : Cookie(device)
94     , device(device)
95     , image(image)
96     , alloc(alloc)
97     , create_info(create_info)
98 {
99 	if (default_view != VK_NULL_HANDLE)
100 	{
101 		ImageViewCreateInfo info;
102 		info.image = this;
103 		info.format = create_info.format;
104 		info.base_level = 0;
105 		info.levels = create_info.levels;
106 		info.base_layer = 0;
107 		info.layers = create_info.layers;
108 		view = ImageViewHandle(device->handle_pool.image_views.allocate(device, default_view, info));
109 	}
110 }
111 
~Image()112 Image::~Image()
113 {
114 	if (alloc.get_memory())
115 	{
116 		if (internal_sync)
117 		{
118 			device->destroy_image_nolock(image);
119 			device->free_memory_nolock(alloc);
120 		}
121 		else
122 		{
123 			device->destroy_image(image);
124 			device->free_memory(alloc);
125 		}
126 	}
127 }
128 
get_host_visible_buffer() const129 const Buffer &LinearHostImage::get_host_visible_buffer() const
130 {
131 	return *cpu_image;
132 }
133 
need_staging_copy() const134 bool LinearHostImage::need_staging_copy() const
135 {
136 	return gpu_image->get_create_info().domain != ImageDomain::LinearHostCached &&
137 	       gpu_image->get_create_info().domain != ImageDomain::LinearHost;
138 }
139 
get_host_visible_allocation() const140 const DeviceAllocation &LinearHostImage::get_host_visible_allocation() const
141 {
142 	return need_staging_copy() ? cpu_image->get_allocation() : gpu_image->get_allocation();
143 }
144 
get_view() const145 const ImageView &LinearHostImage::get_view() const
146 {
147 	return gpu_image->get_view();
148 }
149 
get_image() const150 const Image &LinearHostImage::get_image() const
151 {
152 	return *gpu_image;
153 }
154 
get_offset() const155 size_t LinearHostImage::get_offset() const
156 {
157 	return row_offset;
158 }
159 
get_row_pitch_bytes() const160 size_t LinearHostImage::get_row_pitch_bytes() const
161 {
162 	return row_pitch;
163 }
164 
get_used_pipeline_stages() const165 VkPipelineStageFlags LinearHostImage::get_used_pipeline_stages() const
166 {
167 	return stages;
168 }
169 
LinearHostImage(Device * device,ImageHandle gpu_image_,BufferHandle cpu_image_,VkPipelineStageFlags stages)170 LinearHostImage::LinearHostImage(Device *device, ImageHandle gpu_image_, BufferHandle cpu_image_, VkPipelineStageFlags stages)
171 	: device(device), gpu_image(move(gpu_image_)), cpu_image(move(cpu_image_)), stages(stages)
172 {
173 	if (gpu_image->get_create_info().domain == ImageDomain::LinearHostCached ||
174 	    gpu_image->get_create_info().domain == ImageDomain::LinearHost)
175 	{
176 		VkImageSubresource sub = {};
177 		sub.aspectMask = format_to_aspect_mask(gpu_image->get_format());
178 		VkSubresourceLayout layout;
179 		vkGetImageSubresourceLayout(device->get_device(), gpu_image->get_image(), &sub, &layout);
180 		row_pitch = layout.rowPitch;
181 		row_offset = layout.offset;
182 	}
183 	else
184 	{
185 		row_pitch = gpu_image->get_width() * TextureFormatLayout::format_block_size(gpu_image->get_format());
186 		row_offset = 0;
187 	}
188 }
189 
operator ()(ImageView * view)190 void ImageViewDeleter::operator()(ImageView *view)
191 {
192 	view->device->handle_pool.image_views.free(view);
193 }
194 
operator ()(Image * image)195 void ImageDeleter::operator()(Image *image)
196 {
197 	image->device->handle_pool.images.free(image);
198 }
199 
operator ()(LinearHostImage * image)200 void LinearHostImageDeleter::operator()(LinearHostImage *image)
201 {
202 	image->device->handle_pool.linear_images.free(image);
203 }
204 }
205