~ppsspp/ppsspp/ppsspp_1.3.0

« back to all changes in this revision

Viewing changes to Common/Vulkan/VulkanImage.cpp

  • Committer: Sérgio Benjamim
  • Date: 2017-01-02 00:12:05 UTC
  • Revision ID: sergio_br2@yahoo.com.br-20170102001205-cxbta9za203nmjwm
1.3.0 source (from ppsspp_1.3.0-r160.p5.l1762.a165.t83~56~ubuntu16.04.1.tar.xz).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "Common/Vulkan/VulkanImage.h"
 
2
#include "Common/Vulkan/VulkanMemory.h"
 
3
 
 
4
VkResult VulkanTexture::Create(int w, int h, VkFormat format) {
 
5
        tex_width = w;
 
6
        tex_height = h;
 
7
        format_ = format;
 
8
 
 
9
        VkFormatProperties formatProps;
 
10
        vkGetPhysicalDeviceFormatProperties(vulkan_->GetPhysicalDevice(), format, &formatProps);
 
11
 
 
12
        // See if we can use a linear tiled image for a texture, if not, we will need a staging image for the texture data.
 
13
        // Linear tiling is usually only supported for 2D non-array textures.
 
14
        // needStaging = (!(formatProps.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) ? true : false;
 
15
        // Always stage.
 
16
        needStaging = true;
 
17
 
 
18
        return VK_SUCCESS;
 
19
}
 
20
 
 
21
void VulkanTexture::CreateMappableImage() {
 
22
        // If we already have a mappableImage, forget it.
 
23
        if (mappableImage) {
 
24
                vulkan_->Delete().QueueDeleteImage(mappableImage);
 
25
                mappableImage = VK_NULL_HANDLE;
 
26
        }
 
27
        if (mappableMemory) {
 
28
                vulkan_->Delete().QueueDeleteDeviceMemory(mappableMemory);
 
29
                mappableMemory = VK_NULL_HANDLE;
 
30
        }
 
31
 
 
32
        bool U_ASSERT_ONLY pass;
 
33
 
 
34
        VkImageCreateInfo image_create_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
 
35
        image_create_info.imageType = VK_IMAGE_TYPE_2D;
 
36
        image_create_info.format = format_;
 
37
        image_create_info.extent.width = tex_width;
 
38
        image_create_info.extent.height = tex_height;
 
39
        image_create_info.extent.depth = 1;
 
40
        image_create_info.mipLevels = 1;
 
41
        image_create_info.arrayLayers = 1;
 
42
        image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
 
43
        image_create_info.tiling = VK_IMAGE_TILING_LINEAR;
 
44
        image_create_info.usage = needStaging ? VK_IMAGE_USAGE_TRANSFER_SRC_BIT : VK_IMAGE_USAGE_SAMPLED_BIT;
 
45
        image_create_info.queueFamilyIndexCount = 0;
 
46
        image_create_info.pQueueFamilyIndices = NULL;
 
47
        image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
 
48
        image_create_info.flags = 0;
 
49
        image_create_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
 
50
 
 
51
        VkMemoryAllocateInfo mem_alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
 
52
        mem_alloc.allocationSize = 0;
 
53
        mem_alloc.memoryTypeIndex = 0;
 
54
 
 
55
        // Create a mappable image.  It will be the texture if linear images are ok to be textures
 
56
        // or it will be the staging image if they are not.
 
57
        VkResult res = vkCreateImage(vulkan_->GetDevice(), &image_create_info, NULL, &mappableImage);
 
58
        assert(res == VK_SUCCESS);
 
59
 
 
60
        vkGetImageMemoryRequirements(vulkan_->GetDevice(), mappableImage, &mem_reqs);
 
61
        assert(res == VK_SUCCESS);
 
62
 
 
63
        mem_alloc.allocationSize = mem_reqs.size;
 
64
 
 
65
        // Find the memory type that is host mappable.
 
66
        pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &mem_alloc.memoryTypeIndex);
 
67
        assert(pass);
 
68
 
 
69
        res = vkAllocateMemory(vulkan_->GetDevice(), &mem_alloc, NULL, &mappableMemory);
 
70
        assert(res == VK_SUCCESS);
 
71
 
 
72
        res = vkBindImageMemory(vulkan_->GetDevice(), mappableImage, mappableMemory, 0);
 
73
        assert(res == VK_SUCCESS);
 
74
}
 
75
 
 
76
uint8_t *VulkanTexture::Lock(int level, int *rowPitch) {
 
77
        CreateMappableImage();
 
78
 
 
79
        VkImageSubresource subres = {};
 
80
        subres.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 
81
        subres.mipLevel = 0;
 
82
        subres.arrayLayer = 0;
 
83
 
 
84
        VkSubresourceLayout layout;
 
85
        void *data;
 
86
 
 
87
        // Get the subresource layout so we know what the row pitch is
 
88
        vkGetImageSubresourceLayout(vulkan_->GetDevice(), mappableImage, &subres, &layout);
 
89
        VkResult res = vkMapMemory(vulkan_->GetDevice(), mappableMemory, layout.offset, layout.size, 0, &data);
 
90
        assert(res == VK_SUCCESS);
 
91
 
 
92
        *rowPitch = (int)layout.rowPitch;
 
93
        return (uint8_t *)data;
 
94
}
 
95
 
 
96
void VulkanTexture::Unlock() {
 
97
        vkUnmapMemory(vulkan_->GetDevice(), mappableMemory);
 
98
 
 
99
        VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
 
100
 
 
101
        // if we already have an image, queue it for destruction and forget it.
 
102
        Wipe();
 
103
        if (!needStaging) {
 
104
                // If we can use the linear tiled image as a texture, just do it
 
105
                image = mappableImage;
 
106
                mem = mappableMemory;
 
107
                TransitionImageLayout(cmd, image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
 
108
                // Make sure we don't accidentally delete the main image.
 
109
                mappableImage = VK_NULL_HANDLE;
 
110
                mappableMemory = VK_NULL_HANDLE;
 
111
        } else {
 
112
                VkImageCreateInfo image_create_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
 
113
                image_create_info.imageType = VK_IMAGE_TYPE_2D;
 
114
                image_create_info.format = format_;
 
115
                image_create_info.extent.width = tex_width;
 
116
                image_create_info.extent.height = tex_height;
 
117
                image_create_info.extent.depth = 1;
 
118
                image_create_info.mipLevels = 1;
 
119
                image_create_info.arrayLayers = 1;
 
120
                image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
 
121
                image_create_info.queueFamilyIndexCount = 0;
 
122
                image_create_info.pQueueFamilyIndices = NULL;
 
123
                image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
 
124
                image_create_info.flags = 0;
 
125
                // The mappable image cannot be our texture, so create an optimally tiled image and blit to it
 
126
                image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
 
127
                image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
 
128
                image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
 
129
 
 
130
                VkResult res = vkCreateImage(vulkan_->GetDevice(), &image_create_info, NULL, &image);
 
131
                assert(res == VK_SUCCESS);
 
132
 
 
133
                vkGetImageMemoryRequirements(vulkan_->GetDevice(), image, &mem_reqs);
 
134
 
 
135
                VkMemoryAllocateInfo mem_alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
 
136
                mem_alloc.memoryTypeIndex = 0;
 
137
                mem_alloc.allocationSize = mem_reqs.size;
 
138
 
 
139
                // Find memory type - don't specify any mapping requirements
 
140
                bool pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &mem_alloc.memoryTypeIndex);
 
141
                assert(pass);
 
142
 
 
143
                res = vkAllocateMemory(vulkan_->GetDevice(), &mem_alloc, NULL, &mem);
 
144
                assert(res == VK_SUCCESS);
 
145
 
 
146
                res = vkBindImageMemory(vulkan_->GetDevice(), image, mem, 0);
 
147
                assert(res == VK_SUCCESS);
 
148
 
 
149
                // Since we're going to blit from the mappable image, set its layout to SOURCE_OPTIMAL
 
150
                TransitionImageLayout(cmd, mappableImage,
 
151
                        VK_IMAGE_ASPECT_COLOR_BIT,
 
152
                        VK_IMAGE_LAYOUT_PREINITIALIZED,
 
153
                        VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
 
154
 
 
155
                TransitionImageLayout(cmd, image,
 
156
                        VK_IMAGE_ASPECT_COLOR_BIT,
 
157
                        VK_IMAGE_LAYOUT_UNDEFINED,
 
158
                        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
 
159
 
 
160
                VkImageCopy copy_region;
 
161
                copy_region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 
162
                copy_region.srcSubresource.mipLevel = 0;
 
163
                copy_region.srcSubresource.baseArrayLayer = 0;
 
164
                copy_region.srcSubresource.layerCount = 1;
 
165
                copy_region.srcOffset.x = 0;
 
166
                copy_region.srcOffset.y = 0;
 
167
                copy_region.srcOffset.z = 0;
 
168
                copy_region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 
169
                copy_region.dstSubresource.mipLevel = 0;
 
170
                copy_region.dstSubresource.baseArrayLayer = 0;
 
171
                copy_region.dstSubresource.layerCount = 1;
 
172
                copy_region.dstOffset.x = 0;
 
173
                copy_region.dstOffset.y = 0;
 
174
                copy_region.dstOffset.z = 0;
 
175
                copy_region.extent.width = tex_width;
 
176
                copy_region.extent.height = tex_height;
 
177
                copy_region.extent.depth = 1;
 
178
 
 
179
                // Put the copy command into the command buffer
 
180
                vkCmdCopyImage(cmd,
 
181
                        mappableImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
 
182
                        image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
 
183
                        1, &copy_region);
 
184
 
 
185
                assert(res == VK_SUCCESS);
 
186
 
 
187
                // Set the layout for the texture image from DESTINATION_OPTIMAL to SHADER_READ_ONLY
 
188
                TransitionImageLayout(cmd, image,
 
189
                        VK_IMAGE_ASPECT_COLOR_BIT,
 
190
                        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
 
191
                        VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
 
192
 
 
193
                // Then drop the temporary mappable image - although should not be necessary...
 
194
                vulkan_->Delete().QueueDeleteImage(mappableImage);
 
195
                vulkan_->Delete().QueueDeleteDeviceMemory(mappableMemory);
 
196
 
 
197
                mappableImage = VK_NULL_HANDLE;
 
198
                mappableMemory = VK_NULL_HANDLE;
 
199
        }
 
200
 
 
201
        VkImageViewCreateInfo view_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
 
202
        view_info.image = image;
 
203
        view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
 
204
        view_info.format = format_;
 
205
        view_info.components.r = VK_COMPONENT_SWIZZLE_R;
 
206
        view_info.components.g = VK_COMPONENT_SWIZZLE_G;
 
207
        view_info.components.b = VK_COMPONENT_SWIZZLE_B;
 
208
        view_info.components.a = VK_COMPONENT_SWIZZLE_A;
 
209
        view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 
210
        view_info.subresourceRange.baseMipLevel = 0;
 
211
        view_info.subresourceRange.levelCount = 1;
 
212
        view_info.subresourceRange.baseArrayLayer = 0;
 
213
        view_info.subresourceRange.layerCount = 1;
 
214
        VkResult res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view);
 
215
        assert(res == VK_SUCCESS);
 
216
}
 
217
 
 
218
void VulkanTexture::Wipe() {
 
219
        if (image) {
 
220
                vulkan_->Delete().QueueDeleteImage(image);
 
221
                image = VK_NULL_HANDLE;
 
222
        }
 
223
        if (view) {
 
224
                vulkan_->Delete().QueueDeleteImageView(view);
 
225
                view = VK_NULL_HANDLE;
 
226
        }
 
227
        if (mem && !allocator_) {
 
228
                vulkan_->Delete().QueueDeleteDeviceMemory(mem);
 
229
                mem = VK_NULL_HANDLE;
 
230
        } else if (mem) {
 
231
                allocator_->Free(mem, offset_);
 
232
                mem = VK_NULL_HANDLE;
 
233
        }
 
234
}
 
235
 
 
236
static bool IsDepthStencilFormat(VkFormat format) {
 
237
        switch (format) {
 
238
        case VK_FORMAT_D16_UNORM:
 
239
        case VK_FORMAT_D16_UNORM_S8_UINT:
 
240
        case VK_FORMAT_D24_UNORM_S8_UINT:
 
241
        case VK_FORMAT_D32_SFLOAT:
 
242
        case VK_FORMAT_D32_SFLOAT_S8_UINT:
 
243
                return true;
 
244
        default:
 
245
                return false;
 
246
        }
 
247
}
 
248
 
 
249
bool VulkanTexture::CreateDirect(int w, int h, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage, const VkComponentMapping *mapping) {
 
250
        Wipe();
 
251
 
 
252
        VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
 
253
 
 
254
        tex_width = w;
 
255
        tex_height = h;
 
256
        numMips_ = numMips;
 
257
        format_ = format;
 
258
 
 
259
        VkImageAspectFlags aspect = IsDepthStencilFormat(format) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
 
260
 
 
261
        VkImageCreateInfo image_create_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
 
262
        image_create_info.imageType = VK_IMAGE_TYPE_2D;
 
263
        image_create_info.format = format_;
 
264
        image_create_info.extent.width = tex_width;
 
265
        image_create_info.extent.height = tex_height;
 
266
        image_create_info.extent.depth = 1;
 
267
        image_create_info.mipLevels = numMips;
 
268
        image_create_info.arrayLayers = 1;
 
269
        image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
 
270
        image_create_info.flags = 0;
 
271
        image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
 
272
        image_create_info.usage = usage;
 
273
        if (initialLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) {
 
274
                image_create_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
 
275
        } else {
 
276
                image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
 
277
        }
 
278
 
 
279
        VkResult res = vkCreateImage(vulkan_->GetDevice(), &image_create_info, NULL, &image);
 
280
        if (res != VK_SUCCESS) {
 
281
                assert(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS);
 
282
                return false;
 
283
        }
 
284
 
 
285
        // Write a command to transition the image to the requested layout, if it's not already that layout.
 
286
        if (initialLayout != VK_IMAGE_LAYOUT_UNDEFINED && initialLayout != VK_IMAGE_LAYOUT_PREINITIALIZED) {
 
287
                TransitionImageLayout(cmd, image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, initialLayout);
 
288
        }
 
289
 
 
290
        vkGetImageMemoryRequirements(vulkan_->GetDevice(), image, &mem_reqs);
 
291
 
 
292
        if (allocator_) {
 
293
                offset_ = allocator_->Allocate(mem_reqs, &mem);
 
294
                if (offset_ == VulkanDeviceAllocator::ALLOCATE_FAILED) {
 
295
                        return false;
 
296
                }
 
297
        } else {
 
298
                VkMemoryAllocateInfo mem_alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
 
299
                mem_alloc.memoryTypeIndex = 0;
 
300
                mem_alloc.allocationSize = mem_reqs.size;
 
301
 
 
302
                // Find memory type - don't specify any mapping requirements
 
303
                bool pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &mem_alloc.memoryTypeIndex);
 
304
                assert(pass);
 
305
 
 
306
                res = vkAllocateMemory(vulkan_->GetDevice(), &mem_alloc, NULL, &mem);
 
307
                if (res != VK_SUCCESS) {
 
308
                        assert(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS);
 
309
                        return false;
 
310
                }
 
311
 
 
312
                offset_ = 0;
 
313
        }
 
314
 
 
315
        res = vkBindImageMemory(vulkan_->GetDevice(), image, mem, offset_);
 
316
        if (res != VK_SUCCESS) {
 
317
                assert(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS);
 
318
                return false;
 
319
        }
 
320
 
 
321
        // Create the view while we're at it.
 
322
        VkImageViewCreateInfo view_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
 
323
        view_info.image = image;
 
324
        view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
 
325
        view_info.format = format_;
 
326
        if (mapping) {
 
327
                view_info.components = *mapping;
 
328
        } else {
 
329
                view_info.components.r = VK_COMPONENT_SWIZZLE_R;
 
330
                view_info.components.g = VK_COMPONENT_SWIZZLE_G;
 
331
                view_info.components.b = VK_COMPONENT_SWIZZLE_B;
 
332
                view_info.components.a = VK_COMPONENT_SWIZZLE_A;
 
333
        }
 
334
        view_info.subresourceRange.aspectMask = aspect;
 
335
        view_info.subresourceRange.baseMipLevel = 0;
 
336
        view_info.subresourceRange.levelCount = numMips;
 
337
        view_info.subresourceRange.baseArrayLayer = 0;
 
338
        view_info.subresourceRange.layerCount = 1;
 
339
 
 
340
        res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view);
 
341
        if (res != VK_SUCCESS) {
 
342
                assert(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS);
 
343
                return false;
 
344
        }
 
345
        return true;
 
346
}
 
347
 
 
348
void VulkanTexture::UploadMip(int mip, int mipWidth, int mipHeight, VkBuffer buffer, uint32_t offset, size_t rowLength) {
 
349
        VkBufferImageCopy copy_region = {};
 
350
        copy_region.bufferOffset = offset;
 
351
        copy_region.bufferRowLength = (uint32_t)rowLength;
 
352
        copy_region.bufferImageHeight = 0;  // 2D
 
353
        copy_region.imageExtent.width = mipWidth;
 
354
        copy_region.imageExtent.height = mipHeight;
 
355
        copy_region.imageExtent.depth = 1;
 
356
        copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 
357
        copy_region.imageSubresource.mipLevel = mip;
 
358
        copy_region.imageSubresource.baseArrayLayer = 0;
 
359
        copy_region.imageSubresource.layerCount = 1;
 
360
 
 
361
        VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
 
362
        vkCmdCopyBufferToImage(cmd, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copy_region);
 
363
}
 
364
 
 
365
void VulkanTexture::EndCreate() {
 
366
        VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
 
367
        TransitionImageLayout(cmd, image,
 
368
                VK_IMAGE_ASPECT_COLOR_BIT,
 
369
                VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
 
370
                VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
 
371
}
 
372
 
 
373
void VulkanTexture::Destroy() {
 
374
        if (view) {
 
375
                vulkan_->Delete().QueueDeleteImageView(view);
 
376
        }
 
377
        if (image) {
 
378
                vulkan_->Delete().QueueDeleteImage(image);
 
379
                if (mappableImage == image) {
 
380
                        mappableImage = VK_NULL_HANDLE;
 
381
                }
 
382
        }
 
383
        if (mem && !allocator_) {
 
384
                vulkan_->Delete().QueueDeleteDeviceMemory(mem);
 
385
                if (mappableMemory == mem) {
 
386
                        mappableMemory = VK_NULL_HANDLE;
 
387
                }
 
388
        } else if (mem) {
 
389
                allocator_->Free(mem, offset_);
 
390
        }
 
391
 
 
392
        view = VK_NULL_HANDLE;
 
393
        image = VK_NULL_HANDLE;
 
394
        mem = VK_NULL_HANDLE;
 
395
}