mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-26 23:10:38 +00:00
Split out VulkanTexture from VulkanContext.cpp/h into VulkanImage.cpp/h
This commit is contained in:
parent
3744008d1f
commit
da50370328
@ -242,6 +242,7 @@
|
||||
<ClInclude Include="Timer.h" />
|
||||
<ClInclude Include="Vulkan\SPIRVDisasm.h" />
|
||||
<ClInclude Include="Vulkan\VulkanContext.h" />
|
||||
<ClInclude Include="Vulkan\VulkanImage.h" />
|
||||
<ClInclude Include="Vulkan\VulkanLoader.h" />
|
||||
<ClInclude Include="x64Analyzer.h" />
|
||||
<ClInclude Include="x64Emitter.h" />
|
||||
@ -313,6 +314,7 @@
|
||||
<ClCompile Include="Timer.cpp" />
|
||||
<ClCompile Include="Vulkan\SPIRVDisasm.cpp" />
|
||||
<ClCompile Include="Vulkan\VulkanContext.cpp" />
|
||||
<ClCompile Include="Vulkan\VulkanImage.cpp" />
|
||||
<ClCompile Include="Vulkan\VulkanLoader.cpp" />
|
||||
<ClCompile Include="x64Analyzer.cpp" />
|
||||
<ClCompile Include="x64Emitter.cpp" />
|
||||
|
@ -67,6 +67,9 @@
|
||||
<ClInclude Include="Vulkan\VulkanContext.h">
|
||||
<Filter>Vulkan</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Vulkan\VulkanImage.h">
|
||||
<Filter>Vulkan</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp" />
|
||||
@ -121,6 +124,9 @@
|
||||
<ClCompile Include="Vulkan\VulkanContext.cpp">
|
||||
<Filter>Vulkan</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Vulkan\VulkanImage.cpp">
|
||||
<Filter>Vulkan</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
|
@ -42,6 +42,8 @@ static const char *validationLayers[] = {
|
||||
*/
|
||||
};
|
||||
|
||||
static VkBool32 CheckLayers(const std::vector<layer_properties> &layer_props, const std::vector<const char *> &layer_names);
|
||||
|
||||
VulkanContext::VulkanContext(const char *app_name, int app_ver, uint32_t flags)
|
||||
: device_(nullptr),
|
||||
gfx_queue_(VK_NULL_HANDLE),
|
||||
@ -581,7 +583,7 @@ VkResult VulkanContext::InitDeviceLayerProperties() {
|
||||
* Return 1 (true) if all layer names specified in check_names
|
||||
* can be found in given layer properties.
|
||||
*/
|
||||
VkBool32 CheckLayers(const std::vector<layer_properties> &layer_props, const std::vector<const char *> &layer_names) {
|
||||
static VkBool32 CheckLayers(const std::vector<layer_properties> &layer_props, const std::vector<const char *> &layer_names) {
|
||||
uint32_t check_count = (uint32_t)layer_names.size();
|
||||
uint32_t layer_count = (uint32_t)layer_props.size();
|
||||
for (uint32_t i = 0; i < check_count; i++) {
|
||||
@ -1188,361 +1190,6 @@ void VulkanContext::InitCommandPool() {
|
||||
assert(res == VK_SUCCESS);
|
||||
}
|
||||
|
||||
VkResult VulkanTexture::Create(int w, int h, VkFormat format) {
|
||||
tex_width = w;
|
||||
tex_height = h;
|
||||
format_ = format;
|
||||
|
||||
VkFormatProperties formatProps;
|
||||
vkGetPhysicalDeviceFormatProperties(vulkan_->GetPhysicalDevice(), format, &formatProps);
|
||||
|
||||
// See if we can use a linear tiled image for a texture, if not, we will need a staging image for the texture data.
|
||||
// Linear tiling is usually only supported for 2D non-array textures.
|
||||
// needStaging = (!(formatProps.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) ? true : false;
|
||||
// Always stage.
|
||||
needStaging = true;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
void VulkanTexture::CreateMappableImage() {
|
||||
// If we already have a mappableImage, forget it.
|
||||
if (mappableImage) {
|
||||
vulkan_->Delete().QueueDeleteImage(mappableImage);
|
||||
mappableImage = VK_NULL_HANDLE;
|
||||
}
|
||||
if (mappableMemory) {
|
||||
vulkan_->Delete().QueueDeleteDeviceMemory(mappableMemory);
|
||||
mappableMemory = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
bool U_ASSERT_ONLY pass;
|
||||
|
||||
VkImageCreateInfo image_create_info = {};
|
||||
image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
image_create_info.pNext = NULL;
|
||||
image_create_info.imageType = VK_IMAGE_TYPE_2D;
|
||||
image_create_info.format = format_;
|
||||
image_create_info.extent.width = tex_width;
|
||||
image_create_info.extent.height = tex_height;
|
||||
image_create_info.extent.depth = 1;
|
||||
image_create_info.mipLevels = 1;
|
||||
image_create_info.arrayLayers = 1;
|
||||
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
image_create_info.tiling = VK_IMAGE_TILING_LINEAR;
|
||||
image_create_info.usage = needStaging ? VK_IMAGE_USAGE_TRANSFER_SRC_BIT : VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
image_create_info.queueFamilyIndexCount = 0;
|
||||
image_create_info.pQueueFamilyIndices = NULL;
|
||||
image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
image_create_info.flags = 0;
|
||||
image_create_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
|
||||
|
||||
VkMemoryAllocateInfo mem_alloc = {};
|
||||
mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
mem_alloc.pNext = NULL;
|
||||
mem_alloc.allocationSize = 0;
|
||||
mem_alloc.memoryTypeIndex = 0;
|
||||
|
||||
// Create a mappable image. It will be the texture if linear images are ok to be textures
|
||||
// or it will be the staging image if they are not.
|
||||
VkResult res = vkCreateImage(vulkan_->GetDevice(), &image_create_info, NULL, &mappableImage);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
vkGetImageMemoryRequirements(vulkan_->GetDevice(), mappableImage, &mem_reqs);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
mem_alloc.allocationSize = mem_reqs.size;
|
||||
|
||||
// Find the memory type that is host mappable.
|
||||
pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &mem_alloc.memoryTypeIndex);
|
||||
assert(pass);
|
||||
|
||||
res = vkAllocateMemory(vulkan_->GetDevice(), &mem_alloc, NULL, &mappableMemory);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
res = vkBindImageMemory(vulkan_->GetDevice(), mappableImage, mappableMemory, 0);
|
||||
assert(res == VK_SUCCESS);
|
||||
}
|
||||
|
||||
uint8_t *VulkanTexture::Lock(int level, int *rowPitch) {
|
||||
CreateMappableImage();
|
||||
|
||||
VkImageSubresource subres = {};
|
||||
subres.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
subres.mipLevel = 0;
|
||||
subres.arrayLayer = 0;
|
||||
|
||||
VkSubresourceLayout layout;
|
||||
void *data;
|
||||
|
||||
// Get the subresource layout so we know what the row pitch is
|
||||
vkGetImageSubresourceLayout(vulkan_->GetDevice(), mappableImage, &subres, &layout);
|
||||
VkResult res = vkMapMemory(vulkan_->GetDevice(), mappableMemory, layout.offset, layout.size, 0, &data);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
*rowPitch = (int)layout.rowPitch;
|
||||
return (uint8_t *)data;
|
||||
}
|
||||
|
||||
void VulkanTexture::Unlock() {
|
||||
vkUnmapMemory(vulkan_->GetDevice(), mappableMemory);
|
||||
|
||||
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
|
||||
|
||||
// if we already have an image, queue it for destruction and forget it.
|
||||
Wipe();
|
||||
if (!needStaging) {
|
||||
// If we can use the linear tiled image as a texture, just do it
|
||||
image = mappableImage;
|
||||
mem = mappableMemory;
|
||||
TransitionImageLayout(cmd, image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
// Make sure we don't accidentally delete the main image.
|
||||
mappableImage = VK_NULL_HANDLE;
|
||||
mappableMemory = VK_NULL_HANDLE;
|
||||
} else {
|
||||
VkImageCreateInfo image_create_info = {};
|
||||
image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
image_create_info.pNext = NULL;
|
||||
image_create_info.imageType = VK_IMAGE_TYPE_2D;
|
||||
image_create_info.format = format_;
|
||||
image_create_info.extent.width = tex_width;
|
||||
image_create_info.extent.height = tex_height;
|
||||
image_create_info.extent.depth = 1;
|
||||
image_create_info.mipLevels = 1;
|
||||
image_create_info.arrayLayers = 1;
|
||||
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
image_create_info.queueFamilyIndexCount = 0;
|
||||
image_create_info.pQueueFamilyIndices = NULL;
|
||||
image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
image_create_info.flags = 0;
|
||||
// The mappable image cannot be our texture, so create an optimally tiled image and blit to it
|
||||
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
VkResult res = vkCreateImage(vulkan_->GetDevice(), &image_create_info, NULL, &image);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
vkGetImageMemoryRequirements(vulkan_->GetDevice(), image, &mem_reqs);
|
||||
|
||||
VkMemoryAllocateInfo mem_alloc = {};
|
||||
mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
mem_alloc.pNext = NULL;
|
||||
mem_alloc.memoryTypeIndex = 0;
|
||||
mem_alloc.allocationSize = mem_reqs.size;
|
||||
|
||||
// Find memory type - don't specify any mapping requirements
|
||||
bool pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &mem_alloc.memoryTypeIndex);
|
||||
assert(pass);
|
||||
|
||||
res = vkAllocateMemory(vulkan_->GetDevice(), &mem_alloc, NULL, &mem);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
res = vkBindImageMemory(vulkan_->GetDevice(), image, mem, 0);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
// Since we're going to blit from the mappable image, set its layout to SOURCE_OPTIMAL
|
||||
TransitionImageLayout(cmd, mappableImage,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_PREINITIALIZED,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
|
||||
TransitionImageLayout(cmd, image,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
|
||||
VkImageCopy copy_region;
|
||||
copy_region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
copy_region.srcSubresource.mipLevel = 0;
|
||||
copy_region.srcSubresource.baseArrayLayer = 0;
|
||||
copy_region.srcSubresource.layerCount = 1;
|
||||
copy_region.srcOffset.x = 0;
|
||||
copy_region.srcOffset.y = 0;
|
||||
copy_region.srcOffset.z = 0;
|
||||
copy_region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
copy_region.dstSubresource.mipLevel = 0;
|
||||
copy_region.dstSubresource.baseArrayLayer = 0;
|
||||
copy_region.dstSubresource.layerCount = 1;
|
||||
copy_region.dstOffset.x = 0;
|
||||
copy_region.dstOffset.y = 0;
|
||||
copy_region.dstOffset.z = 0;
|
||||
copy_region.extent.width = tex_width;
|
||||
copy_region.extent.height = tex_height;
|
||||
copy_region.extent.depth = 1;
|
||||
|
||||
// Put the copy command into the command buffer
|
||||
vkCmdCopyImage(cmd,
|
||||
mappableImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
1, ©_region);
|
||||
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
// Set the layout for the texture image from DESTINATION_OPTIMAL to SHADER_READ_ONLY
|
||||
TransitionImageLayout(cmd, image,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
||||
// Then drop the temporary mappable image - although should not be necessary...
|
||||
vulkan_->Delete().QueueDeleteImage(mappableImage);
|
||||
vulkan_->Delete().QueueDeleteDeviceMemory(mappableMemory);
|
||||
|
||||
mappableImage = VK_NULL_HANDLE;
|
||||
mappableMemory = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
VkImageViewCreateInfo view_info = {};
|
||||
view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
view_info.pNext = NULL;
|
||||
view_info.image = VK_NULL_HANDLE;
|
||||
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
view_info.format = format_;
|
||||
view_info.components.r = VK_COMPONENT_SWIZZLE_R;
|
||||
view_info.components.g = VK_COMPONENT_SWIZZLE_G;
|
||||
view_info.components.b = VK_COMPONENT_SWIZZLE_B;
|
||||
view_info.components.a = VK_COMPONENT_SWIZZLE_A;
|
||||
view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
view_info.subresourceRange.baseMipLevel = 0;
|
||||
view_info.subresourceRange.levelCount = 1;
|
||||
view_info.subresourceRange.baseArrayLayer = 0;
|
||||
view_info.subresourceRange.layerCount = 1;
|
||||
view_info.image = image;
|
||||
VkResult res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view);
|
||||
assert(res == VK_SUCCESS);
|
||||
}
|
||||
|
||||
void VulkanTexture::Wipe() {
|
||||
if (image) {
|
||||
vulkan_->Delete().QueueDeleteImage(image);
|
||||
image = VK_NULL_HANDLE;
|
||||
}
|
||||
if (view) {
|
||||
vulkan_->Delete().QueueDeleteImageView(view);
|
||||
view = VK_NULL_HANDLE;
|
||||
}
|
||||
if (mem) {
|
||||
vulkan_->Delete().QueueDeleteDeviceMemory(mem);
|
||||
mem = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanTexture::CreateDirect(int w, int h, int numMips, VkFormat format) {
|
||||
Wipe();
|
||||
|
||||
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
|
||||
|
||||
tex_width = w;
|
||||
tex_height = h;
|
||||
numMips_ = numMips;
|
||||
format_ = format;
|
||||
|
||||
VkImageCreateInfo image_create_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
|
||||
image_create_info.imageType = VK_IMAGE_TYPE_2D;
|
||||
image_create_info.format = format_;
|
||||
image_create_info.extent.width = tex_width;
|
||||
image_create_info.extent.height = tex_height;
|
||||
image_create_info.extent.depth = 1;
|
||||
image_create_info.mipLevels = numMips;
|
||||
image_create_info.arrayLayers = 1;
|
||||
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
image_create_info.flags = 0;
|
||||
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
VkResult res = vkCreateImage(vulkan_->GetDevice(), &image_create_info, NULL, &image);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
vkGetImageMemoryRequirements(vulkan_->GetDevice(), image, &mem_reqs);
|
||||
VkMemoryAllocateInfo mem_alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
|
||||
mem_alloc.memoryTypeIndex = 0;
|
||||
mem_alloc.allocationSize = mem_reqs.size;
|
||||
|
||||
// Find memory type - don't specify any mapping requirements
|
||||
bool pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &mem_alloc.memoryTypeIndex);
|
||||
assert(pass);
|
||||
|
||||
res = vkAllocateMemory(vulkan_->GetDevice(), &mem_alloc, NULL, &mem);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
res = vkBindImageMemory(vulkan_->GetDevice(), image, mem, 0);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
// Since we're going to blit to the target, set its layout to TRANSFER_DST
|
||||
TransitionImageLayout(cmd, image,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
|
||||
// Create the view while we're at it.
|
||||
VkImageViewCreateInfo view_info = {};
|
||||
view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
view_info.pNext = NULL;
|
||||
view_info.image = VK_NULL_HANDLE;
|
||||
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
view_info.format = format_;
|
||||
view_info.components.r = VK_COMPONENT_SWIZZLE_R;
|
||||
view_info.components.g = VK_COMPONENT_SWIZZLE_G;
|
||||
view_info.components.b = VK_COMPONENT_SWIZZLE_B;
|
||||
view_info.components.a = VK_COMPONENT_SWIZZLE_A;
|
||||
view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
view_info.subresourceRange.baseMipLevel = 0;
|
||||
view_info.subresourceRange.levelCount = numMips;
|
||||
view_info.subresourceRange.baseArrayLayer = 0;
|
||||
view_info.subresourceRange.layerCount = 1;
|
||||
view_info.image = image;
|
||||
res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view);
|
||||
assert(res == VK_SUCCESS);
|
||||
}
|
||||
|
||||
void VulkanTexture::UploadMip(int mip, int mipWidth, int mipHeight, VkBuffer buffer, size_t offset, size_t rowLength) {
|
||||
VkBufferImageCopy copy_region = {};
|
||||
copy_region.bufferOffset = offset;
|
||||
copy_region.bufferRowLength = (uint32_t)rowLength;
|
||||
copy_region.bufferImageHeight = 0; // 2D
|
||||
copy_region.imageExtent.width = mipWidth;
|
||||
copy_region.imageExtent.height = mipHeight;
|
||||
copy_region.imageExtent.depth = 1;
|
||||
copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
copy_region.imageSubresource.mipLevel = mip;
|
||||
copy_region.imageSubresource.baseArrayLayer = 0;
|
||||
copy_region.imageSubresource.layerCount = 1;
|
||||
|
||||
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
|
||||
vkCmdCopyBufferToImage(cmd, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©_region);
|
||||
}
|
||||
|
||||
void VulkanTexture::EndCreate() {
|
||||
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
|
||||
TransitionImageLayout(cmd, image,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
}
|
||||
|
||||
void VulkanTexture::Destroy() {
|
||||
if (view) {
|
||||
vulkan_->Delete().QueueDeleteImageView(view);
|
||||
}
|
||||
if (image) {
|
||||
vulkan_->Delete().QueueDeleteImage(image);
|
||||
if (mappableImage == image) {
|
||||
mappableImage = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
if (mem) {
|
||||
vulkan_->Delete().QueueDeleteDeviceMemory(mem);
|
||||
if (mappableMemory == mem) {
|
||||
mappableMemory = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
view = VK_NULL_HANDLE;
|
||||
image = VK_NULL_HANDLE;
|
||||
mem = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
VkFence VulkanContext::CreateFence(bool presignalled) {
|
||||
VkFence fence;
|
||||
VkFenceCreateInfo fenceInfo;
|
||||
@ -1889,22 +1536,3 @@ const char *VulkanResultToString(VkResult res) {
|
||||
void VulkanAssertImpl(VkResult check, const char *function, const char *file, int line) {
|
||||
const char *error = "(none)";
|
||||
}
|
||||
|
||||
void VulkanFramebuffer::Create(VulkanContext *vulkan, int w, int h, VkFormat format) {
|
||||
|
||||
}
|
||||
// void TransitionToImage()
|
||||
|
||||
void VulkanFramebuffer::BeginPass(VkCommandBuffer cmd) {
|
||||
|
||||
}
|
||||
void VulkanFramebuffer::EndPass(VkCommandBuffer cmd) {
|
||||
|
||||
}
|
||||
void VulkanFramebuffer::TransitionToTexture(VkCommandBuffer cmd) {
|
||||
|
||||
}
|
||||
|
||||
VkImageView VulkanFramebuffer::GetColorImageView() {
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
@ -340,71 +340,6 @@ private:
|
||||
std::vector<VkCommandBuffer> cmdQueue_;
|
||||
};
|
||||
|
||||
// Wrapper around what you need to use a texture.
|
||||
// Not very optimal - if you have many small textures you should use other strategies.
|
||||
// Only supports simple 2D textures for now. Mipmap support will be added later.
|
||||
class VulkanTexture {
|
||||
public:
|
||||
VulkanTexture(VulkanContext *vulkan)
|
||||
: vulkan_(vulkan), image(VK_NULL_HANDLE), mem(VK_NULL_HANDLE), view(VK_NULL_HANDLE),
|
||||
tex_width(0), tex_height(0), numMips_(1), format_(VK_FORMAT_UNDEFINED),
|
||||
mappableImage(VK_NULL_HANDLE), mappableMemory(VK_NULL_HANDLE), needStaging(false) {
|
||||
memset(&mem_reqs, 0, sizeof(mem_reqs));
|
||||
}
|
||||
~VulkanTexture() {
|
||||
Destroy();
|
||||
}
|
||||
|
||||
// Simple usage - no cleverness, no mipmaps.
|
||||
// Always call Create, Lock, Unlock. Unlock performs the upload if necessary.
|
||||
// Can later Lock and Unlock again. This cannot change the format. Create cannot
|
||||
// be called a second time without recreating the texture object until Destroy has
|
||||
// been called.
|
||||
VkResult Create(int w, int h, VkFormat format);
|
||||
uint8_t *Lock(int level, int *rowPitch);
|
||||
void Unlock();
|
||||
|
||||
// Fast uploads from buffer. Mipmaps supported.
|
||||
void CreateDirect(int w, int h, int numMips, VkFormat format);
|
||||
void UploadMip(int mip, int mipWidth, int mipHeight, VkBuffer buffer, size_t offset, size_t rowLength); // rowLength is in pixels
|
||||
void EndCreate();
|
||||
int GetNumMips() const { return numMips_; }
|
||||
void Destroy();
|
||||
|
||||
VkImageView GetImageView() const { return view; }
|
||||
|
||||
private:
|
||||
void CreateMappableImage();
|
||||
void Wipe();
|
||||
VulkanContext *vulkan_;
|
||||
VkImage image;
|
||||
VkDeviceMemory mem;
|
||||
VkImageView view;
|
||||
int32_t tex_width, tex_height, numMips_;
|
||||
VkFormat format_;
|
||||
VkImage mappableImage;
|
||||
VkDeviceMemory mappableMemory;
|
||||
VkMemoryRequirements mem_reqs;
|
||||
bool needStaging;
|
||||
};
|
||||
|
||||
// Placeholder
|
||||
|
||||
class VulkanFramebuffer {
|
||||
public:
|
||||
void Create(VulkanContext *vulkan, int w, int h, VkFormat format);
|
||||
|
||||
void BeginPass(VkCommandBuffer cmd);
|
||||
void EndPass(VkCommandBuffer cmd);
|
||||
void TransitionToTexture(VkCommandBuffer cmd);
|
||||
|
||||
VkImageView GetColorImageView();
|
||||
|
||||
private:
|
||||
VkImage image_;
|
||||
VkFramebuffer framebuffer_;
|
||||
};
|
||||
|
||||
// Use these to push vertex, index and uniform data. Generally you'll have two of these
|
||||
// and alternate on each frame.
|
||||
// TODO: Make it possible to suballocate pushbuffers from a large DeviceMemory block.
|
||||
@ -505,16 +440,8 @@ private:
|
||||
uint8_t *writePtr_;
|
||||
};
|
||||
|
||||
|
||||
VkBool32 CheckLayers(const std::vector<layer_properties> &layer_props, const std::vector<const char *> &layer_names);
|
||||
|
||||
// Stand-alone utility functions
|
||||
void VulkanBeginCommandBuffer(VkCommandBuffer cmd);
|
||||
|
||||
void init_glslang();
|
||||
void finalize_glslang();
|
||||
|
||||
bool GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *pshader, std::vector<uint32_t> &spirv, std::string *errorMessage = nullptr);
|
||||
|
||||
void TransitionImageLayout(
|
||||
VkCommandBuffer cmd,
|
||||
VkImage image,
|
||||
@ -522,5 +449,10 @@ void TransitionImageLayout(
|
||||
VkImageLayout old_image_layout,
|
||||
VkImageLayout new_image_layout);
|
||||
|
||||
// GLSL compiler
|
||||
void init_glslang();
|
||||
void finalize_glslang();
|
||||
bool GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *pshader, std::vector<uint32_t> &spirv, std::string *errorMessage = nullptr);
|
||||
|
||||
#endif // UTIL_INIT
|
||||
|
||||
|
356
Common/Vulkan/VulkanImage.cpp
Normal file
356
Common/Vulkan/VulkanImage.cpp
Normal file
@ -0,0 +1,356 @@
|
||||
#include "Common/Vulkan/VulkanImage.h"
|
||||
|
||||
VkResult VulkanTexture::Create(int w, int h, VkFormat format) {
|
||||
tex_width = w;
|
||||
tex_height = h;
|
||||
format_ = format;
|
||||
|
||||
VkFormatProperties formatProps;
|
||||
vkGetPhysicalDeviceFormatProperties(vulkan_->GetPhysicalDevice(), format, &formatProps);
|
||||
|
||||
// See if we can use a linear tiled image for a texture, if not, we will need a staging image for the texture data.
|
||||
// Linear tiling is usually only supported for 2D non-array textures.
|
||||
// needStaging = (!(formatProps.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) ? true : false;
|
||||
// Always stage.
|
||||
needStaging = true;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
void VulkanTexture::CreateMappableImage() {
|
||||
// If we already have a mappableImage, forget it.
|
||||
if (mappableImage) {
|
||||
vulkan_->Delete().QueueDeleteImage(mappableImage);
|
||||
mappableImage = VK_NULL_HANDLE;
|
||||
}
|
||||
if (mappableMemory) {
|
||||
vulkan_->Delete().QueueDeleteDeviceMemory(mappableMemory);
|
||||
mappableMemory = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
bool U_ASSERT_ONLY pass;
|
||||
|
||||
VkImageCreateInfo image_create_info = {};
|
||||
image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
image_create_info.pNext = NULL;
|
||||
image_create_info.imageType = VK_IMAGE_TYPE_2D;
|
||||
image_create_info.format = format_;
|
||||
image_create_info.extent.width = tex_width;
|
||||
image_create_info.extent.height = tex_height;
|
||||
image_create_info.extent.depth = 1;
|
||||
image_create_info.mipLevels = 1;
|
||||
image_create_info.arrayLayers = 1;
|
||||
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
image_create_info.tiling = VK_IMAGE_TILING_LINEAR;
|
||||
image_create_info.usage = needStaging ? VK_IMAGE_USAGE_TRANSFER_SRC_BIT : VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
image_create_info.queueFamilyIndexCount = 0;
|
||||
image_create_info.pQueueFamilyIndices = NULL;
|
||||
image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
image_create_info.flags = 0;
|
||||
image_create_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
|
||||
|
||||
VkMemoryAllocateInfo mem_alloc = {};
|
||||
mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
mem_alloc.pNext = NULL;
|
||||
mem_alloc.allocationSize = 0;
|
||||
mem_alloc.memoryTypeIndex = 0;
|
||||
|
||||
// Create a mappable image. It will be the texture if linear images are ok to be textures
|
||||
// or it will be the staging image if they are not.
|
||||
VkResult res = vkCreateImage(vulkan_->GetDevice(), &image_create_info, NULL, &mappableImage);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
vkGetImageMemoryRequirements(vulkan_->GetDevice(), mappableImage, &mem_reqs);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
mem_alloc.allocationSize = mem_reqs.size;
|
||||
|
||||
// Find the memory type that is host mappable.
|
||||
pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &mem_alloc.memoryTypeIndex);
|
||||
assert(pass);
|
||||
|
||||
res = vkAllocateMemory(vulkan_->GetDevice(), &mem_alloc, NULL, &mappableMemory);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
res = vkBindImageMemory(vulkan_->GetDevice(), mappableImage, mappableMemory, 0);
|
||||
assert(res == VK_SUCCESS);
|
||||
}
|
||||
|
||||
uint8_t *VulkanTexture::Lock(int level, int *rowPitch) {
|
||||
CreateMappableImage();
|
||||
|
||||
VkImageSubresource subres = {};
|
||||
subres.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
subres.mipLevel = 0;
|
||||
subres.arrayLayer = 0;
|
||||
|
||||
VkSubresourceLayout layout;
|
||||
void *data;
|
||||
|
||||
// Get the subresource layout so we know what the row pitch is
|
||||
vkGetImageSubresourceLayout(vulkan_->GetDevice(), mappableImage, &subres, &layout);
|
||||
VkResult res = vkMapMemory(vulkan_->GetDevice(), mappableMemory, layout.offset, layout.size, 0, &data);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
*rowPitch = (int)layout.rowPitch;
|
||||
return (uint8_t *)data;
|
||||
}
|
||||
|
||||
void VulkanTexture::Unlock() {
|
||||
vkUnmapMemory(vulkan_->GetDevice(), mappableMemory);
|
||||
|
||||
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
|
||||
|
||||
// if we already have an image, queue it for destruction and forget it.
|
||||
Wipe();
|
||||
if (!needStaging) {
|
||||
// If we can use the linear tiled image as a texture, just do it
|
||||
image = mappableImage;
|
||||
mem = mappableMemory;
|
||||
TransitionImageLayout(cmd, image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
// Make sure we don't accidentally delete the main image.
|
||||
mappableImage = VK_NULL_HANDLE;
|
||||
mappableMemory = VK_NULL_HANDLE;
|
||||
} else {
|
||||
VkImageCreateInfo image_create_info = {};
|
||||
image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
image_create_info.pNext = NULL;
|
||||
image_create_info.imageType = VK_IMAGE_TYPE_2D;
|
||||
image_create_info.format = format_;
|
||||
image_create_info.extent.width = tex_width;
|
||||
image_create_info.extent.height = tex_height;
|
||||
image_create_info.extent.depth = 1;
|
||||
image_create_info.mipLevels = 1;
|
||||
image_create_info.arrayLayers = 1;
|
||||
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
image_create_info.queueFamilyIndexCount = 0;
|
||||
image_create_info.pQueueFamilyIndices = NULL;
|
||||
image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
image_create_info.flags = 0;
|
||||
// The mappable image cannot be our texture, so create an optimally tiled image and blit to it
|
||||
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
VkResult res = vkCreateImage(vulkan_->GetDevice(), &image_create_info, NULL, &image);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
vkGetImageMemoryRequirements(vulkan_->GetDevice(), image, &mem_reqs);
|
||||
|
||||
VkMemoryAllocateInfo mem_alloc = {};
|
||||
mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
mem_alloc.pNext = NULL;
|
||||
mem_alloc.memoryTypeIndex = 0;
|
||||
mem_alloc.allocationSize = mem_reqs.size;
|
||||
|
||||
// Find memory type - don't specify any mapping requirements
|
||||
bool pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &mem_alloc.memoryTypeIndex);
|
||||
assert(pass);
|
||||
|
||||
res = vkAllocateMemory(vulkan_->GetDevice(), &mem_alloc, NULL, &mem);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
res = vkBindImageMemory(vulkan_->GetDevice(), image, mem, 0);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
// Since we're going to blit from the mappable image, set its layout to SOURCE_OPTIMAL
|
||||
TransitionImageLayout(cmd, mappableImage,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_PREINITIALIZED,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
|
||||
TransitionImageLayout(cmd, image,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
|
||||
VkImageCopy copy_region;
|
||||
copy_region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
copy_region.srcSubresource.mipLevel = 0;
|
||||
copy_region.srcSubresource.baseArrayLayer = 0;
|
||||
copy_region.srcSubresource.layerCount = 1;
|
||||
copy_region.srcOffset.x = 0;
|
||||
copy_region.srcOffset.y = 0;
|
||||
copy_region.srcOffset.z = 0;
|
||||
copy_region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
copy_region.dstSubresource.mipLevel = 0;
|
||||
copy_region.dstSubresource.baseArrayLayer = 0;
|
||||
copy_region.dstSubresource.layerCount = 1;
|
||||
copy_region.dstOffset.x = 0;
|
||||
copy_region.dstOffset.y = 0;
|
||||
copy_region.dstOffset.z = 0;
|
||||
copy_region.extent.width = tex_width;
|
||||
copy_region.extent.height = tex_height;
|
||||
copy_region.extent.depth = 1;
|
||||
|
||||
// Put the copy command into the command buffer
|
||||
vkCmdCopyImage(cmd,
|
||||
mappableImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
1, ©_region);
|
||||
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
// Set the layout for the texture image from DESTINATION_OPTIMAL to SHADER_READ_ONLY
|
||||
TransitionImageLayout(cmd, image,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
||||
// Then drop the temporary mappable image - although should not be necessary...
|
||||
vulkan_->Delete().QueueDeleteImage(mappableImage);
|
||||
vulkan_->Delete().QueueDeleteDeviceMemory(mappableMemory);
|
||||
|
||||
mappableImage = VK_NULL_HANDLE;
|
||||
mappableMemory = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
VkImageViewCreateInfo view_info = {};
|
||||
view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
view_info.pNext = NULL;
|
||||
view_info.image = VK_NULL_HANDLE;
|
||||
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
view_info.format = format_;
|
||||
view_info.components.r = VK_COMPONENT_SWIZZLE_R;
|
||||
view_info.components.g = VK_COMPONENT_SWIZZLE_G;
|
||||
view_info.components.b = VK_COMPONENT_SWIZZLE_B;
|
||||
view_info.components.a = VK_COMPONENT_SWIZZLE_A;
|
||||
view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
view_info.subresourceRange.baseMipLevel = 0;
|
||||
view_info.subresourceRange.levelCount = 1;
|
||||
view_info.subresourceRange.baseArrayLayer = 0;
|
||||
view_info.subresourceRange.layerCount = 1;
|
||||
view_info.image = image;
|
||||
VkResult res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view);
|
||||
assert(res == VK_SUCCESS);
|
||||
}
|
||||
|
||||
void VulkanTexture::Wipe() {
|
||||
if (image) {
|
||||
vulkan_->Delete().QueueDeleteImage(image);
|
||||
image = VK_NULL_HANDLE;
|
||||
}
|
||||
if (view) {
|
||||
vulkan_->Delete().QueueDeleteImageView(view);
|
||||
view = VK_NULL_HANDLE;
|
||||
}
|
||||
if (mem) {
|
||||
vulkan_->Delete().QueueDeleteDeviceMemory(mem);
|
||||
mem = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanTexture::CreateDirect(int w, int h, int numMips, VkFormat format, VkImageUsageFlags usage) {
|
||||
Wipe();
|
||||
|
||||
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
|
||||
|
||||
tex_width = w;
|
||||
tex_height = h;
|
||||
numMips_ = numMips;
|
||||
format_ = format;
|
||||
|
||||
VkImageCreateInfo image_create_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
|
||||
image_create_info.imageType = VK_IMAGE_TYPE_2D;
|
||||
image_create_info.format = format_;
|
||||
image_create_info.extent.width = tex_width;
|
||||
image_create_info.extent.height = tex_height;
|
||||
image_create_info.extent.depth = 1;
|
||||
image_create_info.mipLevels = numMips;
|
||||
image_create_info.arrayLayers = 1;
|
||||
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
image_create_info.flags = 0;
|
||||
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
VkResult res = vkCreateImage(vulkan_->GetDevice(), &image_create_info, NULL, &image);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
vkGetImageMemoryRequirements(vulkan_->GetDevice(), image, &mem_reqs);
|
||||
VkMemoryAllocateInfo mem_alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
|
||||
mem_alloc.memoryTypeIndex = 0;
|
||||
mem_alloc.allocationSize = mem_reqs.size;
|
||||
|
||||
// Find memory type - don't specify any mapping requirements
|
||||
bool pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &mem_alloc.memoryTypeIndex);
|
||||
assert(pass);
|
||||
|
||||
res = vkAllocateMemory(vulkan_->GetDevice(), &mem_alloc, NULL, &mem);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
res = vkBindImageMemory(vulkan_->GetDevice(), image, mem, 0);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
// Since we're going to blit to the target, set its layout to TRANSFER_DST
|
||||
TransitionImageLayout(cmd, image,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
|
||||
// Create the view while we're at it.
|
||||
VkImageViewCreateInfo view_info = {};
|
||||
view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
view_info.pNext = NULL;
|
||||
view_info.image = VK_NULL_HANDLE;
|
||||
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
view_info.format = format_;
|
||||
view_info.components.r = VK_COMPONENT_SWIZZLE_R;
|
||||
view_info.components.g = VK_COMPONENT_SWIZZLE_G;
|
||||
view_info.components.b = VK_COMPONENT_SWIZZLE_B;
|
||||
view_info.components.a = VK_COMPONENT_SWIZZLE_A;
|
||||
view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
view_info.subresourceRange.baseMipLevel = 0;
|
||||
view_info.subresourceRange.levelCount = numMips;
|
||||
view_info.subresourceRange.baseArrayLayer = 0;
|
||||
view_info.subresourceRange.layerCount = 1;
|
||||
view_info.image = image;
|
||||
res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view);
|
||||
assert(res == VK_SUCCESS);
|
||||
}
|
||||
|
||||
void VulkanTexture::UploadMip(int mip, int mipWidth, int mipHeight, VkBuffer buffer, size_t offset, size_t rowLength) {
|
||||
VkBufferImageCopy copy_region = {};
|
||||
copy_region.bufferOffset = offset;
|
||||
copy_region.bufferRowLength = (uint32_t)rowLength;
|
||||
copy_region.bufferImageHeight = 0; // 2D
|
||||
copy_region.imageExtent.width = mipWidth;
|
||||
copy_region.imageExtent.height = mipHeight;
|
||||
copy_region.imageExtent.depth = 1;
|
||||
copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
copy_region.imageSubresource.mipLevel = mip;
|
||||
copy_region.imageSubresource.baseArrayLayer = 0;
|
||||
copy_region.imageSubresource.layerCount = 1;
|
||||
|
||||
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
|
||||
vkCmdCopyBufferToImage(cmd, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©_region);
|
||||
}
|
||||
|
||||
void VulkanTexture::EndCreate() {
|
||||
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
|
||||
TransitionImageLayout(cmd, image,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
}
|
||||
|
||||
void VulkanTexture::Destroy() {
|
||||
if (view) {
|
||||
vulkan_->Delete().QueueDeleteImageView(view);
|
||||
}
|
||||
if (image) {
|
||||
vulkan_->Delete().QueueDeleteImage(image);
|
||||
if (mappableImage == image) {
|
||||
mappableImage = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
if (mem) {
|
||||
vulkan_->Delete().QueueDeleteDeviceMemory(mem);
|
||||
if (mappableMemory == mem) {
|
||||
mappableMemory = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
view = VK_NULL_HANDLE;
|
||||
image = VK_NULL_HANDLE;
|
||||
mem = VK_NULL_HANDLE;
|
||||
}
|
50
Common/Vulkan/VulkanImage.h
Normal file
50
Common/Vulkan/VulkanImage.h
Normal file
@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include "Common/Vulkan/VulkanContext.h"
|
||||
|
||||
// Wrapper around what you need to use a texture.
|
||||
// Not very optimal - if you have many small textures you should use other strategies.
|
||||
class VulkanTexture {
|
||||
public:
|
||||
VulkanTexture(VulkanContext *vulkan)
|
||||
: vulkan_(vulkan), image(VK_NULL_HANDLE), mem(VK_NULL_HANDLE), view(VK_NULL_HANDLE),
|
||||
tex_width(0), tex_height(0), numMips_(1), format_(VK_FORMAT_UNDEFINED),
|
||||
mappableImage(VK_NULL_HANDLE), mappableMemory(VK_NULL_HANDLE), needStaging(false) {
|
||||
memset(&mem_reqs, 0, sizeof(mem_reqs));
|
||||
}
|
||||
~VulkanTexture() {
|
||||
Destroy();
|
||||
}
|
||||
|
||||
// Simple usage - no cleverness, no mipmaps.
|
||||
// Always call Create, Lock, Unlock. Unlock performs the upload if necessary.
|
||||
// Can later Lock and Unlock again. This cannot change the format. Create cannot
|
||||
// be called a second time without recreating the texture object until Destroy has
|
||||
// been called.
|
||||
VkResult Create(int w, int h, VkFormat format);
|
||||
uint8_t *Lock(int level, int *rowPitch);
|
||||
void Unlock();
|
||||
|
||||
// Fast uploads from buffer. Mipmaps supported. Usage must at least include VK_IMAGE_USAGE_TRANSFER_DST_BIT in order to use UploadMip.
|
||||
void CreateDirect(int w, int h, int numMips, VkFormat format, VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
|
||||
void UploadMip(int mip, int mipWidth, int mipHeight, VkBuffer buffer, size_t offset, size_t rowLength); // rowLength is in pixels
|
||||
void EndCreate();
|
||||
int GetNumMips() const { return numMips_; }
|
||||
void Destroy();
|
||||
|
||||
VkImageView GetImageView() const { return view; }
|
||||
|
||||
private:
|
||||
void CreateMappableImage();
|
||||
void Wipe();
|
||||
VulkanContext *vulkan_;
|
||||
VkImage image;
|
||||
VkDeviceMemory mem;
|
||||
VkImageView view;
|
||||
int32_t tex_width, tex_height, numMips_;
|
||||
VkFormat format_;
|
||||
VkImage mappableImage;
|
||||
VkDeviceMemory mappableMemory;
|
||||
VkMemoryRequirements mem_reqs;
|
||||
bool needStaging;
|
||||
};
|
@ -51,7 +51,7 @@ namespace DX9 {
|
||||
struct FBO_DX9;
|
||||
}
|
||||
|
||||
class VulkanFramebuffer;
|
||||
class VulkanFBO;
|
||||
|
||||
struct VirtualFramebuffer {
|
||||
int last_frame_used;
|
||||
@ -87,12 +87,13 @@ struct VirtualFramebuffer {
|
||||
int lastFrameNewSize;
|
||||
|
||||
GEBufferFormat format; // virtual, right now they are all RGBA8888
|
||||
|
||||
// TODO: Handle fbo and colorDepth better.
|
||||
u8 colorDepth;
|
||||
union {
|
||||
FBO *fbo;
|
||||
DX9::FBO_DX9 *fbo_dx9;
|
||||
VulkanFramebuffer *fbo_vk;
|
||||
VulkanFBO *fbo_vk;
|
||||
};
|
||||
|
||||
u16 drawnWidth;
|
||||
|
@ -106,8 +106,7 @@ inline int RoundUp4(int x) {
|
||||
}
|
||||
|
||||
// Reads decoded vertex formats in a convenient way. For software transform and debugging.
|
||||
class VertexReader
|
||||
{
|
||||
class VertexReader {
|
||||
public:
|
||||
VertexReader(u8 *base, const DecVtxFormat &decFmt, int vtype) : base_(base), data_(base), decFmt_(decFmt), vtype_(vtype) {}
|
||||
|
||||
|
@ -345,6 +345,7 @@
|
||||
<ClCompile Include="Vulkan\TextureCacheVulkan.cpp" />
|
||||
<ClCompile Include="Vulkan\TextureScalerVulkan.cpp" />
|
||||
<ClCompile Include="Vulkan\VertexShaderGeneratorVulkan.cpp" />
|
||||
<ClCompile Include="Vulkan\VulkanUtil.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Common\Common.vcxproj">
|
||||
@ -354,4 +355,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
@ -458,5 +458,6 @@
|
||||
<ClCompile Include="Vulkan\VertexShaderGeneratorVulkan.cpp">
|
||||
<Filter>Vulkan</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Vulkan\VulkanUtil.cpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -41,10 +41,12 @@
|
||||
|
||||
#include "GPU/GPUInterface.h"
|
||||
#include "GPU/GPUState.h"
|
||||
#include "Common/Vulkan/VulkanImage.h"
|
||||
#include "GPU/Vulkan/FramebufferVulkan.h"
|
||||
#include "GPU/Vulkan/DrawEngineVulkan.h"
|
||||
#include "GPU/Vulkan/TextureCacheVulkan.h"
|
||||
#include "GPU/Vulkan/ShaderManagerVulkan.h"
|
||||
#include "GPU/Vulkan/VulkanUtil.h"
|
||||
|
||||
#include "UI/OnScreenDisplay.h"
|
||||
|
||||
@ -599,7 +601,7 @@ void FramebufferManagerVulkan::ResizeFramebufFBO(VirtualFramebuffer *vfb, u16 w,
|
||||
return;
|
||||
}
|
||||
|
||||
vfb->fbo_vk = new VulkanFramebuffer();
|
||||
vfb->fbo_vk = new VulkanFBO();
|
||||
// bo_create(vfb->renderWidth, vfb->renderHeight, 1, true, (FBOColorDepth)vfb->colorDepth);
|
||||
if (old.fbo_vk) {
|
||||
INFO_LOG(SCEGE, "Resizing FBO for %08x : %i x %i x %i", vfb->fb_address, w, h, vfb->format);
|
||||
@ -777,7 +779,7 @@ void FramebufferManagerVulkan::BlitFramebufferDepth(VirtualFramebuffer *src, Vir
|
||||
}*/
|
||||
}
|
||||
|
||||
VulkanFramebuffer *FramebufferManagerVulkan::GetTempFBO(u16 w, u16 h, VulkanFBOColorDepth depth) {
|
||||
VulkanFBO *FramebufferManagerVulkan::GetTempFBO(u16 w, u16 h, VulkanFBOColorDepth depth) {
|
||||
u64 key = ((u64)depth << 32) | ((u32)w << 16) | h;
|
||||
auto it = tempFBOs_.find(key);
|
||||
if (it != tempFBOs_.end()) {
|
||||
@ -787,7 +789,7 @@ VulkanFramebuffer *FramebufferManagerVulkan::GetTempFBO(u16 w, u16 h, VulkanFBOC
|
||||
|
||||
textureCache_->ForgetLastTexture();
|
||||
// FBO *fbo_vk = fbo_create(w, h, 1, false, depth);
|
||||
VulkanFramebuffer *fbo_vk = new VulkanFramebuffer();
|
||||
VulkanFBO *fbo_vk = new VulkanFBO();
|
||||
if (!fbo_vk)
|
||||
return nullptr;
|
||||
// fbo_bind_as_render_target(fbo_vk);
|
||||
|
@ -36,13 +36,13 @@ class DrawEngineVulkan;
|
||||
class VulkanContext;
|
||||
class ShaderManagerVulkan;
|
||||
class VulkanTexture;
|
||||
class VulkanFramebuffer;
|
||||
|
||||
struct PostShaderUniforms {
|
||||
float texelDelta[2]; float pad[2];
|
||||
float pixelDelta[2]; float pad0[2];
|
||||
float time[4];
|
||||
};
|
||||
|
||||
// Simple struct for asynchronous PBO readbacks
|
||||
// TODO: Probably will need a complete redesign.
|
||||
struct AsyncPBOVulkan {
|
||||
@ -122,7 +122,7 @@ public:
|
||||
|
||||
virtual void RebindFramebuffer() override;
|
||||
|
||||
VulkanFramebuffer *GetTempFBO(u16 w, u16 h, VulkanFBOColorDepth depth = VK_FBO_8888);
|
||||
VulkanFBO *GetTempFBO(u16 w, u16 h, VulkanFBOColorDepth depth = VK_FBO_8888);
|
||||
|
||||
// Cardboard Settings Calculator
|
||||
struct CardboardSettings * GetCardboardSettings(struct CardboardSettings * cardboardSettings);
|
||||
@ -182,7 +182,7 @@ private:
|
||||
bool resized_;
|
||||
|
||||
struct TempFBO {
|
||||
VulkanFramebuffer *fbo_vk;
|
||||
VulkanFBO *fbo_vk;
|
||||
int last_frame_used;
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
#pragma once
|
||||
// Copyright (c) 2012- PPSSPP Project.
|
||||
// Copyright (c) 2016- PPSSPP Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -22,13 +22,16 @@
|
||||
#include "i18n/i18n.h"
|
||||
#include "math/math_util.h"
|
||||
#include "profiler/profiler.h"
|
||||
#include "Common/Vulkan/VulkanContext.h"
|
||||
#include "Common/ColorConv.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/Host.h"
|
||||
#include "Core/MemMap.h"
|
||||
#include "Core/Reporting.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
#include "Common/Vulkan/VulkanContext.h"
|
||||
#include "Common/Vulkan/VulkanImage.h"
|
||||
|
||||
#include "GPU/ge_constants.h"
|
||||
#include "GPU/GPUState.h"
|
||||
#include "GPU/Vulkan/TextureCacheVulkan.h"
|
||||
@ -81,6 +84,10 @@ SamplerCache::~SamplerCache() {
|
||||
}
|
||||
}
|
||||
|
||||
CachedTextureVulkan::~CachedTextureVulkan() {
|
||||
delete texture_;
|
||||
}
|
||||
|
||||
VkSampler SamplerCache::GetOrCreateSampler(const SamplerCacheKey &key) {
|
||||
auto iter = cache_.find(key);
|
||||
if (iter != cache_.end()) {
|
||||
@ -905,9 +912,9 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(VkCommandBuffer cmd, TexCacheEn
|
||||
}
|
||||
if (depal) {
|
||||
// VulkanTexture *clutTexture = depalShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBuf_);
|
||||
VulkanFramebuffer *depalFBO = framebufferManager_->GetTempFBO(framebuffer->renderWidth, framebuffer->renderHeight, VK_FBO_8888);
|
||||
VulkanFBO *depalFBO = framebufferManager_->GetTempFBO(framebuffer->renderWidth, framebuffer->renderHeight, VK_FBO_8888);
|
||||
|
||||
depalFBO->BeginPass(cmd);
|
||||
//depalFBO->BeginPass(cmd);
|
||||
|
||||
struct Pos {
|
||||
Pos(float x_, float y_, float z_) : x(x_), y(y_), z(z_) {
|
||||
@ -1018,9 +1025,9 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(VkCommandBuffer cmd, TexCacheEn
|
||||
glDisableVertexAttribArray(depal->a_position);
|
||||
glDisableVertexAttribArray(depal->a_texcoord0);
|
||||
*/
|
||||
depalFBO->EndPass(cmd);
|
||||
depalFBO->TransitionToTexture(cmd);
|
||||
imageView = depalFBO->GetColorImageView();
|
||||
//depalFBO->EndPass(cmd);
|
||||
//depalFBO->TransitionToTexture(cmd);
|
||||
//imageView = depalFBO->GetColorImageView();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -33,7 +33,7 @@ class ShaderManagerVulkan;
|
||||
class DrawEngineVulkan;
|
||||
|
||||
class VulkanContext;
|
||||
class VulkanImage;
|
||||
class VulkanTexture;
|
||||
|
||||
struct SamplerCacheKey {
|
||||
SamplerCacheKey() : fullKey(0) {}
|
||||
@ -61,9 +61,8 @@ class CachedTextureVulkan {
|
||||
public:
|
||||
CachedTextureVulkan() : texture_(nullptr) {
|
||||
}
|
||||
~CachedTextureVulkan() {
|
||||
delete texture_;
|
||||
}
|
||||
~CachedTextureVulkan();
|
||||
|
||||
// TODO: Switch away from VulkanImage to some kind of smart suballocating texture pool.
|
||||
VulkanTexture *texture_;
|
||||
};
|
||||
|
45
GPU/Vulkan/VulkanUtil.cpp
Normal file
45
GPU/Vulkan/VulkanUtil.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright (c) 2016- PPSSPP Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0 or later versions.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "GPU/Vulkan/VulkanUtil.h"
|
||||
|
||||
VulkanFBO::VulkanFBO() : color_(nullptr), depthStencil_(nullptr) {}
|
||||
|
||||
VulkanFBO::~VulkanFBO() {
|
||||
delete color_;
|
||||
delete depthStencil_;
|
||||
}
|
||||
|
||||
void VulkanFBO::Create(VulkanContext *vulkan, VkRenderPass rp_compatible, int width, int height, VkFormat color_Format) {
|
||||
color_ = new VulkanTexture(vulkan);
|
||||
VkImageCreateFlags flags = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
color_->CreateDirect(width, height, 1, VK_FORMAT_R8G8B8A8_UNORM, flags | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
|
||||
depthStencil_->CreateDirect(width, height, 1, VK_FORMAT_D24_UNORM_S8_UINT, flags | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
||||
|
||||
VkImageView views[2] = { color_->GetImageView(), depthStencil_->GetImageView() };
|
||||
|
||||
VkFramebufferCreateInfo fb = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
|
||||
fb.pAttachments = views;
|
||||
fb.attachmentCount = 2;
|
||||
fb.flags = 0;
|
||||
fb.renderPass = rp_compatible;
|
||||
fb.width = width;
|
||||
fb.height = height;
|
||||
fb.layers = 1;
|
||||
|
||||
vkCreateFramebuffer(vulkan->GetDevice(), &fb, nullptr, &framebuffer_);
|
||||
}
|
@ -1,4 +1,48 @@
|
||||
// Copyright (c) 2016- PPSSPP Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0 or later versions.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/Vulkan/VulkanLoader.h"
|
||||
#include "Common/Vulkan/VulkanImage.h"
|
||||
|
||||
// Vulkan doesn't really have the concept of an FBO that owns the images,
|
||||
// but it does have the concept of a framebuffer as a set of attachments.
|
||||
// VulkanFBO is an approximation of the FBO concept the other backends use
|
||||
// to make things as similar as possible without being suboptimal.
|
||||
//
|
||||
class VulkanFBO {
|
||||
public:
|
||||
VulkanFBO();
|
||||
~VulkanFBO();
|
||||
|
||||
// Depth-format is chosen automatically depending on hardware support.
|
||||
// Color format will be 32-bit RGBA.
|
||||
void Create(VulkanContext *vulkan, VkRenderPass rp_compatible, int width, int height, VkFormat colorFormat);
|
||||
|
||||
VulkanTexture *GetColor() { return color_; }
|
||||
VulkanTexture *GetDepthStencil() { return depthStencil_; }
|
||||
|
||||
VkFramebuffer GetFramebuffer() { return framebuffer_; }
|
||||
|
||||
private:
|
||||
VulkanTexture *color_;
|
||||
VulkanTexture *depthStencil_;
|
||||
|
||||
// This point specifically to color and depth.
|
||||
VkFramebuffer framebuffer_;
|
||||
};
|
@ -127,6 +127,7 @@ EGL_FILES := \
|
||||
VULKAN_FILES := \
|
||||
$(SRC)/Common/Vulkan/VulkanLoader.cpp \
|
||||
$(SRC)/Common/Vulkan/VulkanContext.cpp \
|
||||
$(SRC)/Common/Vulkan/VulkanImage.cpp \
|
||||
$(SRC)/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp \
|
||||
$(SRC)/GPU/Vulkan/DrawEngineVulkan.cpp \
|
||||
$(SRC)/GPU/Vulkan/FramebufferVulkan.cpp \
|
||||
@ -137,7 +138,8 @@ VULKAN_FILES := \
|
||||
$(SRC)/GPU/Vulkan/TextureCacheVulkan.cpp \
|
||||
$(SRC)/GPU/Vulkan/TextureScalerVulkan.cpp \
|
||||
$(SRC)/GPU/Vulkan/DepalettizeShaderVulkan.cpp \
|
||||
$(SRC)/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp
|
||||
$(SRC)/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp \
|
||||
$(SRC)/GPU/Vulkan/VulkanUtil.cpp
|
||||
#endif
|
||||
|
||||
EXEC_AND_LIB_FILES := \
|
||||
|
@ -30,7 +30,9 @@
|
||||
#include "math/lin/matrix4x4.h"
|
||||
#include "math/dataconv.h"
|
||||
#include "thin3d/thin3d.h"
|
||||
|
||||
#include "Common/Vulkan/VulkanContext.h"
|
||||
#include "Common/Vulkan/VulkanImage.h"
|
||||
|
||||
// We use a simple descriptor set for all rendering: 1 sampler, 1 texture, 1 UBO binding point.
|
||||
// binding 0 - uniform data
|
||||
|
Loading…
Reference in New Issue
Block a user