Added ability to retrieve back textures stored on GPU

This commit is contained in:
Juan Linietsky 2019-06-25 19:49:52 -03:00
parent e1b3444415
commit e3905f9af3
7 changed files with 364 additions and 60 deletions

View File

@ -1007,7 +1007,7 @@ uint32_t RenderingDeviceVulkan::get_compressed_image_format_pixel_rshift(DataFor
return 0; return 0;
} }
uint32_t RenderingDeviceVulkan::get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw, uint32_t *r_blockh) { uint32_t RenderingDeviceVulkan::get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw, uint32_t *r_blockh, uint32_t *r_depth) {
uint32_t w = p_width; uint32_t w = p_width;
uint32_t h = p_height; uint32_t h = p_height;
@ -1035,6 +1035,9 @@ uint32_t RenderingDeviceVulkan::get_image_format_required_size(DataFormat p_form
if (r_blockh) { if (r_blockh) {
*r_blockh = bh; *r_blockh = bh;
} }
if (r_depth) {
*r_depth = d;
}
w = MAX(blockw, w >> 1); w = MAX(blockw, w >> 1);
h = MAX(blockh, h >> 1); h = MAX(blockh, h >> 1);
d = MAX(1, d >> 1); d = MAX(1, d >> 1);
@ -1166,6 +1169,17 @@ const VkBorderColor RenderingDeviceVulkan::sampler_border_colors[RenderingDevice
VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE, VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
VK_BORDER_COLOR_INT_OPAQUE_WHITE VK_BORDER_COLOR_INT_OPAQUE_WHITE
}; };
const VkImageType RenderingDeviceVulkan::vulkan_image_type[RenderingDevice::TEXTURE_TYPE_MAX] = {
VK_IMAGE_TYPE_1D,
VK_IMAGE_TYPE_2D,
VK_IMAGE_TYPE_3D,
VK_IMAGE_TYPE_2D,
VK_IMAGE_TYPE_1D,
VK_IMAGE_TYPE_2D,
VK_IMAGE_TYPE_3D
};
/***************************/ /***************************/
/**** BUFFER MANAGEMENT ****/ /**** BUFFER MANAGEMENT ****/
/***************************/ /***************************/
@ -1308,26 +1322,7 @@ Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_
} else { } else {
//flush EVERYTHING including setup commands. IF not immediate, also need to flush the draw commands //flush EVERYTHING including setup commands. IF not immediate, also need to flush the draw commands
context->flush(true, p_on_draw_command_buffer); _flush(true, p_on_draw_command_buffer);
//re-create the setup command
{
VkCommandBufferBeginInfo cmdbuf_begin;
cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cmdbuf_begin.pNext = NULL;
cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
cmdbuf_begin.pInheritanceInfo = NULL;
VkResult err = vkBeginCommandBuffer(frames[frame].setup_command_buffer, &cmdbuf_begin);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
context->set_setup_buffer(frames[frame].setup_command_buffer); //append now so it's added before everything else
if (p_on_draw_command_buffer) {
err = vkBeginCommandBuffer(frames[frame].draw_command_buffer, &cmdbuf_begin);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
context->append_command_buffer(frames[frame].draw_command_buffer);
}
}
//clear the whole staging buffer //clear the whole staging buffer
for (int i = 0; i < staging_buffer_blocks.size(); i++) { for (int i = 0; i < staging_buffer_blocks.size(); i++) {
@ -1371,7 +1366,7 @@ Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_
continue; //and try again continue; //and try again
} else { } else {
context->flush(false); // flush previous frames (but don't touch setup command, so this frame) _flush(false, false);
for (int i = 0; i < staging_buffer_blocks.size(); i++) { for (int i = 0; i < staging_buffer_blocks.size(); i++) {
//clear all blocks but the ones from this frame //clear all blocks but the ones from this frame
@ -1498,19 +1493,9 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
image_create_info.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; image_create_info.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
}*/ }*/
const VkImageType image_type[TEXTURE_TYPE_MAX] = {
VK_IMAGE_TYPE_1D,
VK_IMAGE_TYPE_2D,
VK_IMAGE_TYPE_3D,
VK_IMAGE_TYPE_2D,
VK_IMAGE_TYPE_1D,
VK_IMAGE_TYPE_2D,
VK_IMAGE_TYPE_3D
};
ERR_FAIL_INDEX_V(p_format.type, TEXTURE_TYPE_MAX, RID()); ERR_FAIL_INDEX_V(p_format.type, TEXTURE_TYPE_MAX, RID());
image_create_info.imageType = image_type[p_format.type]; image_create_info.imageType = vulkan_image_type[p_format.type];
ERR_FAIL_COND_V_MSG(p_format.width < 1, RID(), "Width must be equal or greater than 1 for all textures"); ERR_FAIL_COND_V_MSG(p_format.width < 1, RID(), "Width must be equal or greater than 1 for all textures");
@ -1574,6 +1559,9 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
if (p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT) { if (p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT) {
image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
} }
if (p_format.usage_bits & TEXTURE_USAGE_CAN_RETRIEVE_BIT) {
image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
}
image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
image_create_info.queueFamilyIndexCount = 0; image_create_info.queueFamilyIndexCount = 0;
@ -1651,7 +1639,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
VmaAllocationCreateInfo allocInfo; VmaAllocationCreateInfo allocInfo;
allocInfo.flags = 0; allocInfo.flags = 0;
allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; allocInfo.usage = p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT ? VMA_MEMORY_USAGE_CPU_ONLY : VMA_MEMORY_USAGE_GPU_ONLY;
allocInfo.requiredFlags = 0; allocInfo.requiredFlags = 0;
allocInfo.preferredFlags = 0; allocInfo.preferredFlags = 0;
allocInfo.memoryTypeBits = 0; allocInfo.memoryTypeBits = 0;
@ -1906,8 +1894,8 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con
ERR_FAIL_COND_V(p_layer >= layer_count, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_layer >= layer_count, ERR_INVALID_PARAMETER);
uint32_t width, height; uint32_t width, height;
uint32_t image_size = get_image_format_required_size(texture->format, texture->width, texture->height, 1, texture->mipmaps, &width, &height); uint32_t image_size = get_image_format_required_size(texture->format, texture->width, texture->height, texture->depth, texture->mipmaps, &width, &height);
uint32_t required_size = image_size * texture->depth; uint32_t required_size = image_size;
uint32_t required_align = get_compressed_image_format_block_byte_size(texture->format); uint32_t required_align = get_compressed_image_format_block_byte_size(texture->format);
if (required_align == 1) { if (required_align == 1) {
required_align = get_image_format_pixel_size(texture->format); required_align = get_image_format_pixel_size(texture->format);
@ -1950,14 +1938,15 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con
uint32_t mipmap_offset = 0; uint32_t mipmap_offset = 0;
for (uint32_t mm_i = 0; mm_i < texture->mipmaps; mm_i++) { for (uint32_t mm_i = 0; mm_i < texture->mipmaps; mm_i++) {
uint32_t image_total = get_image_format_required_size(texture->format, texture->width, texture->height, 1, mm_i + 1, &width, &height); uint32_t depth;
uint32_t image_total = get_image_format_required_size(texture->format, texture->width, texture->height, texture->depth, mm_i + 1, &width, &height, &depth);
const uint8_t *read_ptr_mipmap = r.ptr() + mipmap_offset; const uint8_t *read_ptr_mipmap = r.ptr() + mipmap_offset;
image_size = image_total - mipmap_offset; image_size = image_total - mipmap_offset;
for (uint32_t z = 0; z < texture->depth; z++) { //for 3D textures, depth may be > 0 for (uint32_t z = 0; z < depth; z++) { //for 3D textures, depth may be > 0
const uint8_t *read_ptr = read_ptr_mipmap + image_size * z; const uint8_t *read_ptr = read_ptr_mipmap + image_size * z / depth;
for (uint32_t x = 0; x < width; x += region_size) { for (uint32_t x = 0; x < width; x += region_size) {
for (uint32_t y = 0; y < height; y += region_size) { for (uint32_t y = 0; y < height; y += region_size) {
@ -2087,6 +2076,260 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con
return OK; return OK;
} }
PoolVector<uint8_t> RenderingDeviceVulkan::_texture_get_data_from_image(Texture *tex, VkImage p_image, VmaAllocation p_allocation, uint32_t p_layer) {
uint32_t width, height, depth;
uint32_t image_size = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, tex->mipmaps, &width, &height, &depth);
PoolVector<uint8_t> image_data;
image_data.resize(image_size);
void *img_mem;
vmaMapMemory(allocator, p_allocation, &img_mem);
uint32_t blockw, blockh;
get_compressed_image_format_block_dimensions(tex->format, blockw, blockh);
uint32_t block_size = get_compressed_image_format_block_byte_size(tex->format);
uint32_t pixel_size = get_image_format_pixel_size(tex->format);
{
PoolVector<uint8_t>::Write w = image_data.write();
uint32_t mipmap_offset = 0;
for (uint32_t mm_i = 0; mm_i < tex->mipmaps; mm_i++) {
uint32_t image_total = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, mm_i + 1, &width, &height, &depth);
uint8_t *write_ptr_mipmap = w.ptr() + mipmap_offset;
image_size = image_total - mipmap_offset;
VkImageSubresource image_sub_resorce;
image_sub_resorce.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
image_sub_resorce.arrayLayer = p_layer;
image_sub_resorce.mipLevel = mm_i;
VkSubresourceLayout layout;
vkGetImageSubresourceLayout(device, p_image, &image_sub_resorce, &layout);
for (uint32_t z = 0; z < depth; z++) {
uint8_t *write_ptr = write_ptr_mipmap + z * image_size / depth;
const uint8_t *slice_read_ptr = ((uint8_t *)img_mem) + layout.offset + z * layout.depthPitch;
if (block_size > 1) {
//compressed
uint32_t line_width = (block_size * (width / blockw));
for (uint32_t y = 0; y < height / blockh; y++) {
const uint8_t *rptr = slice_read_ptr + y * layout.rowPitch;
uint8_t *wptr = write_ptr + y * line_width;
copymem(wptr, rptr, line_width);
}
} else {
//uncompressed
for (uint32_t y = 0; y < height; y++) {
const uint8_t *rptr = slice_read_ptr + y * layout.rowPitch;
uint8_t *wptr = write_ptr + y * pixel_size * width;
copymem(wptr, rptr, pixel_size * width);
}
}
}
mipmap_offset = image_total;
}
}
vmaUnmapMemory(allocator, p_allocation);
return image_data;
}
PoolVector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint32_t p_layer) {
Texture *tex = texture_owner.getornull(p_texture);
ERR_FAIL_COND_V(!tex, PoolVector<uint8_t>());
ERR_FAIL_COND_V_MSG(tex->bound, PoolVector<uint8_t>(),
"Texture can't be retrieved while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture.");
ERR_FAIL_COND_V_MSG(!(tex->usage_flags & TEXTURE_USAGE_CAN_RETRIEVE_BIT), PoolVector<uint8_t>(),
"Texture requires the TEXTURE_USAGE_CAN_RETRIEVE_BIT in order to be retrieved.");
uint32_t layer_count = tex->layers;
if (tex->type == TEXTURE_TYPE_CUBE || tex->type == TEXTURE_TYPE_CUBE_ARRAY) {
layer_count *= 6;
}
ERR_FAIL_COND_V(p_layer >= layer_count, PoolVector<uint8_t>());
if (tex->usage_flags & TEXTURE_USAGE_CPU_READ_BIT) {
//does not need anything fancy, map and read.
return _texture_get_data_from_image(tex, tex->image, tex->allocation, p_layer);
} else {
VkImageCreateInfo image_create_info;
image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
image_create_info.pNext = NULL;
image_create_info.flags = 0;
image_create_info.imageType = vulkan_image_type[tex->type];
image_create_info.format = vulkan_formats[tex->format];
image_create_info.extent.width = tex->width;
image_create_info.extent.height = tex->height;
image_create_info.extent.depth = tex->depth;
image_create_info.mipLevels = tex->mipmaps;
image_create_info.arrayLayers = 1; //for retrieving, only one layer
image_create_info.samples = rasterization_sample_count[tex->samples];
image_create_info.tiling = VK_IMAGE_TILING_LINEAR; // for retrieving, linear is recommended
image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;
image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
image_create_info.queueFamilyIndexCount = 0;
image_create_info.pQueueFamilyIndices = NULL;
image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VmaAllocationCreateInfo allocInfo;
allocInfo.flags = 0;
allocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
allocInfo.requiredFlags = 0;
allocInfo.preferredFlags = 0;
allocInfo.memoryTypeBits = 0;
allocInfo.pool = NULL;
allocInfo.pUserData = NULL;
VkImage image;
VmaAllocation allocation;
VmaAllocationInfo allocation_info;
//Allocate the image
VkResult err = vmaCreateImage(allocator, &image_create_info, &allocInfo, &image, &allocation, &allocation_info);
ERR_FAIL_COND_V(err, PoolVector<uint8_t>());
VkCommandBuffer command_buffer = frames[frame].setup_command_buffer;
//PRE Copy the image
{ //Source
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_memory_barrier.pNext = NULL;
image_memory_barrier.srcAccessMask = 0;
image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
image_memory_barrier.oldLayout = tex->unbound_layout;
image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.image = tex->image;
image_memory_barrier.subresourceRange.aspectMask = tex->aspect_mask;
image_memory_barrier.subresourceRange.baseMipLevel = 0;
image_memory_barrier.subresourceRange.levelCount = tex->mipmaps;
image_memory_barrier.subresourceRange.baseArrayLayer = p_layer;
image_memory_barrier.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier);
}
{ //Dest
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_memory_barrier.pNext = NULL;
image_memory_barrier.srcAccessMask = 0;
image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.image = image;
image_memory_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
image_memory_barrier.subresourceRange.baseMipLevel = 0;
image_memory_barrier.subresourceRange.levelCount = tex->mipmaps;
image_memory_barrier.subresourceRange.baseArrayLayer = 0;
image_memory_barrier.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier);
}
//COPY
{
for (uint32_t i = 0; i < tex->mipmaps; i++) {
uint32_t mm_width, mm_height, mm_depth;
get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, i + 1, &mm_width, &mm_height, &mm_depth);
VkImageCopy image_copy_region;
image_copy_region.srcSubresource.aspectMask = tex->aspect_mask;
image_copy_region.srcSubresource.baseArrayLayer = p_layer;
image_copy_region.srcSubresource.layerCount = 1;
image_copy_region.srcSubresource.mipLevel = i;
image_copy_region.srcOffset.x = 0;
image_copy_region.srcOffset.y = 0;
image_copy_region.srcOffset.z = 0;
image_copy_region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
image_copy_region.dstSubresource.baseArrayLayer = p_layer;
image_copy_region.dstSubresource.layerCount = 1;
image_copy_region.dstSubresource.mipLevel = i;
image_copy_region.dstOffset.x = 0;
image_copy_region.dstOffset.y = 0;
image_copy_region.dstOffset.z = 0;
image_copy_region.extent.width = mm_width;
image_copy_region.extent.height = mm_height;
image_copy_region.extent.depth = mm_depth;
vkCmdCopyImage(command_buffer, tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy_region);
print_line("copying mipmap " + itos(i) + " w: " + itos(mm_width) + " h " + itos(mm_height) + " d " + itos(mm_depth));
}
}
// RESTORE LAYOUT for SRC and DST
{ //restore src
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_memory_barrier.pNext = NULL;
image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
image_memory_barrier.newLayout = tex->unbound_layout;
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.image = tex->image;
image_memory_barrier.subresourceRange.aspectMask = tex->aspect_mask;
image_memory_barrier.subresourceRange.baseMipLevel = 0;
image_memory_barrier.subresourceRange.levelCount = tex->mipmaps;
image_memory_barrier.subresourceRange.baseArrayLayer = p_layer;
image_memory_barrier.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier);
}
{ //make dst readable
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_memory_barrier.pNext = NULL;
image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
image_memory_barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.image = image;
image_memory_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
image_memory_barrier.subresourceRange.baseMipLevel = 0;
image_memory_barrier.subresourceRange.levelCount = tex->mipmaps;
image_memory_barrier.subresourceRange.baseArrayLayer = 0;
image_memory_barrier.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier);
}
//flush everything so memory can be safely mapped
_flush(true, false);
PoolVector<uint8_t> ret = _texture_get_data_from_image(tex, image, allocation, p_layer);
vmaDestroyImage(allocator, image, allocation);
return ret;
}
}
bool RenderingDeviceVulkan::texture_is_shared(RID p_texture) { bool RenderingDeviceVulkan::texture_is_shared(RID p_texture) {
Texture *tex = texture_owner.getornull(p_texture); Texture *tex = texture_owner.getornull(p_texture);
ERR_FAIL_COND_V(!tex, false); ERR_FAIL_COND_V(!tex, false);
@ -5292,6 +5535,42 @@ void RenderingDeviceVulkan::advance_frame() {
} }
} }
void RenderingDeviceVulkan::_flush(bool p_setup, bool p_draw) {
//not doing this crashes RADV (undefined behavior)
if (p_setup) {
vkEndCommandBuffer(frames[frame].setup_command_buffer);
}
if (p_draw) {
vkEndCommandBuffer(frames[frame].draw_command_buffer);
}
context->flush(p_setup, p_draw);
//re-create the setup command
if (p_setup) {
VkCommandBufferBeginInfo cmdbuf_begin;
cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cmdbuf_begin.pNext = NULL;
cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
cmdbuf_begin.pInheritanceInfo = NULL;
VkResult err = vkBeginCommandBuffer(frames[frame].setup_command_buffer, &cmdbuf_begin);
ERR_FAIL_COND(err);
context->set_setup_buffer(frames[frame].setup_command_buffer); //append now so it's added before everything else
}
if (p_draw) {
VkCommandBufferBeginInfo cmdbuf_begin;
cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cmdbuf_begin.pNext = NULL;
cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
cmdbuf_begin.pInheritanceInfo = NULL;
VkResult err = vkBeginCommandBuffer(frames[frame].draw_command_buffer, &cmdbuf_begin);
ERR_FAIL_COND(err);
context->append_command_buffer(frames[frame].draw_command_buffer);
}
}
void RenderingDeviceVulkan::initialize(VulkanContext *p_context) { void RenderingDeviceVulkan::initialize(VulkanContext *p_context) {
context = p_context; context = p_context;
@ -5413,7 +5692,7 @@ void RenderingDeviceVulkan::finalize() {
//free all resources //free all resources
context->flush(false, false); _flush(false, false);
_free_rids(pipeline_owner, "Pipeline"); _free_rids(pipeline_owner, "Pipeline");
_free_rids(uniform_set_owner, "UniformSet"); _free_rids(uniform_set_owner, "UniformSet");

View File

@ -37,6 +37,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
static const VkBlendOp blend_operations[RenderingDevice::BLEND_OP_MAX]; static const VkBlendOp blend_operations[RenderingDevice::BLEND_OP_MAX];
static const VkSamplerAddressMode address_modes[SAMPLER_REPEAT_MODE_MAX]; static const VkSamplerAddressMode address_modes[SAMPLER_REPEAT_MODE_MAX];
static const VkBorderColor sampler_border_colors[SAMPLER_BORDER_COLOR_MAX]; static const VkBorderColor sampler_border_colors[SAMPLER_BORDER_COLOR_MAX];
static const VkImageType vulkan_image_type[TEXTURE_TYPE_MAX];
// Functions used for format // Functions used for format
// validation, and ensures the // validation, and ensures the
@ -47,7 +48,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
static void get_compressed_image_format_block_dimensions(DataFormat p_format, uint32_t &r_w, uint32_t &r_h); static void get_compressed_image_format_block_dimensions(DataFormat p_format, uint32_t &r_w, uint32_t &r_h);
uint32_t get_compressed_image_format_block_byte_size(DataFormat p_format); uint32_t get_compressed_image_format_block_byte_size(DataFormat p_format);
static uint32_t get_compressed_image_format_pixel_rshift(DataFormat p_format); static uint32_t get_compressed_image_format_pixel_rshift(DataFormat p_format);
static uint32_t get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw = NULL, uint32_t *r_blockh = NULL); static uint32_t get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw = NULL, uint32_t *r_blockh = NULL, uint32_t *r_depth = NULL);
static uint32_t get_image_required_mipmaps(uint32_t p_width, uint32_t p_height, uint32_t p_depth); static uint32_t get_image_required_mipmaps(uint32_t p_width, uint32_t p_height, uint32_t p_depth);
/***************************/ /***************************/
@ -116,6 +117,8 @@ class RenderingDeviceVulkan : public RenderingDevice {
RID_Owner<Texture> texture_owner; RID_Owner<Texture> texture_owner;
uint32_t texture_upload_region_size_px; uint32_t texture_upload_region_size_px;
PoolVector<uint8_t> _texture_get_data_from_image(Texture *tex, VkImage p_image, VmaAllocation p_allocation, uint32_t p_layer);
/*****************/ /*****************/
/**** SAMPLER ****/ /**** SAMPLER ****/
/*****************/ /*****************/
@ -701,6 +704,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
VulkanContext *context; VulkanContext *context;
void _free_internal(RID p_id); void _free_internal(RID p_id);
void _flush(bool p_setup, bool p_draw);
bool screen_prepared; bool screen_prepared;
@ -711,6 +715,7 @@ public:
virtual RID texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<PoolVector<uint8_t> > &p_data = Vector<PoolVector<uint8_t> >()); virtual RID texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<PoolVector<uint8_t> > &p_data = Vector<PoolVector<uint8_t> >());
virtual RID texture_create_shared(const TextureView &p_view, RID p_with_texture); virtual RID texture_create_shared(const TextureView &p_view, RID p_with_texture);
virtual Error texture_update(RID p_texture, uint32_t p_layer, const PoolVector<uint8_t> &p_data, bool p_sync_with_draw = false); virtual Error texture_update(RID p_texture, uint32_t p_layer, const PoolVector<uint8_t> &p_data, bool p_sync_with_draw = false);
virtual PoolVector<uint8_t> texture_get_data(RID p_texture, uint32_t p_layer);
virtual bool texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const; virtual bool texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const;
virtual bool texture_is_shared(RID p_texture); virtual bool texture_is_shared(RID p_texture);

View File

@ -1056,9 +1056,6 @@ void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) {
if (p_flush_setup && command_buffer_queue[0]) { if (p_flush_setup && command_buffer_queue[0]) {
//use a fence to wait for everything done //use a fence to wait for everything done
vkResetFences(device, 1, &fences[frame_index]);
VkSubmitInfo submit_info; VkSubmitInfo submit_info;
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.pNext = NULL; submit_info.pNext = NULL;
@ -1069,7 +1066,7 @@ void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) {
submit_info.pCommandBuffers = command_buffer_queue.ptr(); submit_info.pCommandBuffers = command_buffer_queue.ptr();
submit_info.signalSemaphoreCount = 0; submit_info.signalSemaphoreCount = 0;
submit_info.pSignalSemaphores = NULL; submit_info.pSignalSemaphores = NULL;
VkResult err = vkQueueSubmit(graphics_queue, 1, &submit_info, fences[frame_index]); VkResult err = vkQueueSubmit(graphics_queue, 1, &submit_info, VK_NULL_HANDLE);
command_buffer_queue.write[0] = NULL; command_buffer_queue.write[0] = NULL;
ERR_FAIL_COND(err); ERR_FAIL_COND(err);
vkDeviceWaitIdle(device); vkDeviceWaitIdle(device);
@ -1079,8 +1076,6 @@ void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) {
//use a fence to wait for everything done //use a fence to wait for everything done
vkResetFences(device, 1, &fences[frame_index]);
VkSubmitInfo submit_info; VkSubmitInfo submit_info;
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.pNext = NULL; submit_info.pNext = NULL;
@ -1091,8 +1086,7 @@ void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) {
submit_info.pCommandBuffers = command_buffer_queue.ptr() + 1; submit_info.pCommandBuffers = command_buffer_queue.ptr() + 1;
submit_info.signalSemaphoreCount = 0; submit_info.signalSemaphoreCount = 0;
submit_info.pSignalSemaphores = NULL; submit_info.pSignalSemaphores = NULL;
VkResult err = vkQueueSubmit(graphics_queue, 1, &submit_info, fences[frame_index]); VkResult err = vkQueueSubmit(graphics_queue, 1, &submit_info, VK_NULL_HANDLE);
command_buffer_queue.write[0] = NULL;
ERR_FAIL_COND(err); ERR_FAIL_COND(err);
vkDeviceWaitIdle(device); vkDeviceWaitIdle(device);

View File

@ -1,4 +1,5 @@
#include "rasterizer_storage_rd.h" #include "rasterizer_storage_rd.h"
#include "core/engine.h"
Ref<Image> RasterizerStorageRD::_validate_texture_format(const Ref<Image> &p_image, TextureToRDFormat &r_format) { Ref<Image> RasterizerStorageRD::_validate_texture_format(const Ref<Image> &p_image, TextureToRDFormat &r_format) {
@ -487,6 +488,7 @@ RID RasterizerStorageRD::texture_2d_create(const Ref<Image> &p_image) {
texture.mipmaps = p_image->get_mipmap_count() + 1; texture.mipmaps = p_image->get_mipmap_count() + 1;
texture.depth = 1; texture.depth = 1;
texture.format = p_image->get_format(); texture.format = p_image->get_format();
texture.validated_format = image->get_format();
texture.rd_type = RD::TEXTURE_TYPE_2D; texture.rd_type = RD::TEXTURE_TYPE_2D;
texture.rd_format = ret_format.format; texture.rd_format = ret_format.format;
@ -503,7 +505,7 @@ RID RasterizerStorageRD::texture_2d_create(const Ref<Image> &p_image) {
rd_format.mipmaps = texture.mipmaps; rd_format.mipmaps = texture.mipmaps;
rd_format.type = texture.rd_type; rd_format.type = texture.rd_type;
rd_format.samples = RD::TEXTURE_SAMPLES_1; rd_format.samples = RD::TEXTURE_SAMPLES_1;
rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_CAN_RETRIEVE_BIT;
if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) { if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) {
rd_format.shareable_formats.push_back(texture.rd_format); rd_format.shareable_formats.push_back(texture.rd_format);
rd_format.shareable_formats.push_back(texture.rd_format_srgb); rd_format.shareable_formats.push_back(texture.rd_format_srgb);
@ -536,9 +538,6 @@ RID RasterizerStorageRD::texture_2d_create(const Ref<Image> &p_image) {
texture.rd_view = rd_view; texture.rd_view = rd_view;
texture.is_proxy = false; texture.is_proxy = false;
#warning TODO this is temporary to get things to work
texture.image_cache_2d = p_image;
#warning texture owner needs a spinlock to make this really callable from any thread #warning texture owner needs a spinlock to make this really callable from any thread
return texture_owner.make_rid(texture); return texture_owner.make_rid(texture);
} }
@ -588,9 +587,9 @@ void RasterizerStorageRD::_texture_2d_update(RID p_texture, const Ref<Image> &p_
ERR_FAIL_INDEX(p_layer, tex->layers); ERR_FAIL_INDEX(p_layer, tex->layers);
} }
#warning TODO this is temporary to get things to work #ifdef TOOLS_ENABLED
tex->image_cache_2d = p_image; tex->image_cache_2d.unref();
#endif
TextureToRDFormat f; TextureToRDFormat f;
Ref<Image> validated = _validate_texture_format(p_image, f); Ref<Image> validated = _validate_texture_format(p_image, f);
@ -678,8 +677,28 @@ Ref<Image> RasterizerStorageRD::texture_2d_get(RID p_texture) const {
Texture *tex = texture_owner.getornull(p_texture); Texture *tex = texture_owner.getornull(p_texture);
ERR_FAIL_COND_V(!tex, Ref<Image>()); ERR_FAIL_COND_V(!tex, Ref<Image>());
#warning TODO this is temporary to get things to work #ifdef TOOLS_ENABLED
return tex->image_cache_2d; if (tex->image_cache_2d.is_valid()) {
return tex->image_cache_2d;
}
#endif
PoolVector<uint8_t> data = RD::get_singleton()->texture_get_data(tex->rd_texture, 0);
ERR_FAIL_COND_V(data.size() == 0, Ref<Image>());
Ref<Image> image;
image.instance();
image->create(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data);
ERR_FAIL_COND_V(image->empty(), Ref<Image>());
if (tex->format != tex->validated_format) {
image->convert(tex->format);
}
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
tex->image_cache_2d = image;
}
#endif
return image;
} }
Ref<Image> RasterizerStorageRD::texture_2d_layer_get(RID p_texture, int p_layer) const { Ref<Image> RasterizerStorageRD::texture_2d_layer_get(RID p_texture, int p_layer) const {
@ -803,7 +822,7 @@ void RasterizerStorageRD::_update_render_target(RenderTarget *rt) {
rd_format.mipmaps = 1; rd_format.mipmaps = 1;
rd_format.type = RD::TEXTURE_TYPE_2D; rd_format.type = RD::TEXTURE_TYPE_2D;
rd_format.samples = RD::TEXTURE_SAMPLES_1; rd_format.samples = RD::TEXTURE_SAMPLES_1;
rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_RETRIEVE_BIT;
rd_format.shareable_formats.push_back(rt->color_format); rd_format.shareable_formats.push_back(rt->color_format);
rd_format.shareable_formats.push_back(rt->color_format_srgb); rd_format.shareable_formats.push_back(rt->color_format_srgb);
} }

View File

@ -26,6 +26,8 @@ public:
RD::TextureView rd_view; RD::TextureView rd_view;
Image::Format format; Image::Format format;
Image::Format validated_format;
int width; int width;
int height; int height;
int depth; int depth;

View File

@ -294,7 +294,8 @@ public:
TEXTURE_USAGE_STORAGE_ATOMIC_BIT = (1 << 4), TEXTURE_USAGE_STORAGE_ATOMIC_BIT = (1 << 4),
TEXTURE_USAGE_CPU_READ_BIT = (1 << 5), TEXTURE_USAGE_CPU_READ_BIT = (1 << 5),
TEXTURE_USAGE_CAN_UPDATE_BIT = (1 << 6), TEXTURE_USAGE_CAN_UPDATE_BIT = (1 << 6),
TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT = (1 << 7), TEXTURE_USAGE_CAN_RETRIEVE_BIT = (1 << 7),
TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT = (1 << 8),
}; };
enum TextureSwizzle { enum TextureSwizzle {
@ -352,6 +353,7 @@ public:
virtual RID texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<PoolVector<uint8_t> > &p_data = Vector<PoolVector<uint8_t> >()) = 0; virtual RID texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<PoolVector<uint8_t> > &p_data = Vector<PoolVector<uint8_t> >()) = 0;
virtual RID texture_create_shared(const TextureView &p_view, RID p_with_texture) = 0; virtual RID texture_create_shared(const TextureView &p_view, RID p_with_texture) = 0;
virtual Error texture_update(RID p_texture, uint32_t p_layer, const PoolVector<uint8_t> &p_data, bool p_sync_with_draw = false) = 0; //this function can be used from any thread and it takes effect at the begining of the frame, unless sync with draw is used, which is used to mix updates with draw calls virtual Error texture_update(RID p_texture, uint32_t p_layer, const PoolVector<uint8_t> &p_data, bool p_sync_with_draw = false) = 0; //this function can be used from any thread and it takes effect at the begining of the frame, unless sync with draw is used, which is used to mix updates with draw calls
virtual PoolVector<uint8_t> texture_get_data(RID p_texture, uint32_t p_layer) = 0; // CPU textures will return immediately, while GPU textures will most likely force a flush
virtual bool texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const = 0; virtual bool texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const = 0;
virtual bool texture_is_shared(RID p_texture) =0; virtual bool texture_is_shared(RID p_texture) =0;

View File

@ -1635,6 +1635,9 @@ void VisualServer::_bind_methods() {
#warning TODO all texture methods need re-binding #warning TODO all texture methods need re-binding
ClassDB::bind_method(D_METHOD("texture_2d_create", "image"), &VisualServer::texture_2d_create);
ClassDB::bind_method(D_METHOD("texture_2d_get", "texture"), &VisualServer::texture_2d_get);
#ifndef _3D_DISABLED #ifndef _3D_DISABLED
ClassDB::bind_method(D_METHOD("sky_create"), &VisualServer::sky_create); ClassDB::bind_method(D_METHOD("sky_create"), &VisualServer::sky_create);
ClassDB::bind_method(D_METHOD("sky_set_texture", "sky", "cube_map", "radiance_size"), &VisualServer::sky_set_texture); ClassDB::bind_method(D_METHOD("sky_set_texture", "sky", "cube_map", "radiance_size"), &VisualServer::sky_set_texture);