Files
grd/grd-rdp-view-creator-avc.c

1576 lines
58 KiB
C
Raw Normal View History

2026-02-13 13:06:50 +09:00
/*
* Copyright (C) 2024 Pascal Nowack
*
* 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; either version 2 of the
* License, or (at your option) any later version.
*
* 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include "config.h"
#include "grd-rdp-view-creator-avc.h"
#include "grd-debug.h"
#include "grd-image-view-nv12.h"
#include "grd-rdp-buffer.h"
#include "grd-rdp-render-state.h"
#include "grd-utils.h"
#include "grd-vk-buffer.h"
#include "grd-vk-device.h"
#include "grd-vk-image.h"
#include "grd-vk-memory.h"
#include "grd-vk-physical-device.h"
#include "grd-vk-queue.h"
#include "grd-vk-utils.h"
#define N_SPECIALIZATION_CONSTANTS 6
typedef struct
{
uint32_t source_width;
uint32_t source_height;
uint32_t target_width;
uint32_t target_height;
uint32_t perform_dmg_detection;
uint32_t state_buffer_stride;
} ViewCreateInfo;
typedef struct
{
VkCommandBuffer init_state_buffers;
VkCommandBuffer synchronize_state_buffers;
VkCommandBuffer init_layouts;
VkCommandBuffer create_dual_view_simple;
VkCommandBuffer create_dual_view_difference;
} CommandBuffers;
typedef struct
{
GrdRdpViewCreatorAVC *view_creator_avc;
VkPipelineLayout vk_pipeline_layout;
VkPipeline vk_pipeline;
} Pipeline;
struct _GrdRdpViewCreatorAVC
{
GrdRdpViewCreator parent;
GrdVkDevice *device;
gboolean debug_vk_times;
gboolean supports_update_after_bind;
ViewCreateInfo view_create_info;
VkDeviceSize state_buffer_size;
GrdVkBuffer *dmg_buffer_device;
GrdVkBuffer *dmg_buffer_host;
uint32_t *mapped_dmg_buffer;
GrdVkBuffer *chroma_check_buffer_device;
GrdVkBuffer *chroma_check_buffer_host;
uint32_t *mapped_chroma_check_buffer;
VkSampler vk_src_new_sampler;
VkSampler vk_src_old_sampler;
VkDescriptorSetLayout vk_target_descriptor_set_layout;
VkDescriptorSetLayout vk_source_descriptor_set_layout;
VkDescriptorSetLayout vk_state_descriptor_set_layout;
VkDescriptorPool vk_image_descriptor_pool;
VkDescriptorPool vk_buffer_descriptor_pool;
VkDescriptorSet vk_descriptor_set_main_view;
VkDescriptorSet vk_descriptor_set_aux_view;
VkDescriptorSet vk_descriptor_set_state;
VkDescriptorSet vk_descriptor_set_sources;
gboolean pending_view_creation_recording;
gboolean pending_layout_transition;
GrdVkQueue *queue;
VkQueryPool vk_timestamp_query_pool;
VkCommandPool vk_command_pool;
CommandBuffers command_buffers;
VkFence vk_fence;
Pipeline *dual_view_pipeline;
Pipeline *dual_view_dmg_pipeline;
};
G_DEFINE_TYPE (GrdRdpViewCreatorAVC, grd_rdp_view_creator_avc,
GRD_TYPE_RDP_VIEW_CREATOR)
static void
pipeline_free (Pipeline *pipeline);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (Pipeline, pipeline_free)
static void
pipeline_free (Pipeline *pipeline)
{
GrdRdpViewCreatorAVC *view_creator_avc = pipeline->view_creator_avc;
VkDevice vk_device = grd_vk_device_get_device (view_creator_avc->device);
g_assert (vk_device != VK_NULL_HANDLE);
if (pipeline->vk_pipeline != VK_NULL_HANDLE)
vkDestroyPipeline (vk_device, pipeline->vk_pipeline, NULL);
if (pipeline->vk_pipeline_layout != VK_NULL_HANDLE)
vkDestroyPipelineLayout (vk_device, pipeline->vk_pipeline_layout, NULL);
g_free (pipeline);
}
static void
write_image_descriptor_sets (GrdRdpViewCreatorAVC *view_creator_avc,
GrdImageViewNV12 *main_image_view,
GrdImageViewNV12 *aux_image_view,
GrdVkImage *src_image_new,
GrdVkImage *src_image_old)
{
VkDevice vk_device = grd_vk_device_get_device (view_creator_avc->device);
VkWriteDescriptorSet write_descriptor_sets[6] = {};
VkDescriptorImageInfo image_infos[6] = {};
image_infos[0].sampler = VK_NULL_HANDLE;
image_infos[0].imageView = grd_image_view_nv12_get_y_layer (main_image_view);
image_infos[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
image_infos[1] = image_infos[0];
image_infos[1].imageView = grd_image_view_nv12_get_uv_layer (main_image_view);
image_infos[2] = image_infos[0];
image_infos[2].imageView = grd_image_view_nv12_get_y_layer (aux_image_view);
image_infos[3] = image_infos[0];
image_infos[3].imageView = grd_image_view_nv12_get_uv_layer (aux_image_view);
image_infos[4].sampler = view_creator_avc->vk_src_new_sampler;
image_infos[4].imageView = grd_vk_image_get_image_view (src_image_new);
image_infos[4].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
image_infos[5] = image_infos[4];
image_infos[5].sampler = view_creator_avc->vk_src_old_sampler;
if (src_image_old)
image_infos[5].imageView = grd_vk_image_get_image_view (src_image_old);
write_descriptor_sets[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write_descriptor_sets[0].dstSet =
view_creator_avc->vk_descriptor_set_main_view;
write_descriptor_sets[0].dstBinding = 0;
write_descriptor_sets[0].descriptorCount = 1;
write_descriptor_sets[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
write_descriptor_sets[0].pImageInfo = &image_infos[0];
write_descriptor_sets[1] = write_descriptor_sets[0];
write_descriptor_sets[1].dstBinding = 1;
write_descriptor_sets[1].pImageInfo = &image_infos[1];
write_descriptor_sets[2] = write_descriptor_sets[0];
write_descriptor_sets[2].dstSet =
view_creator_avc->vk_descriptor_set_aux_view;
write_descriptor_sets[2].dstBinding = 0;
write_descriptor_sets[2].pImageInfo = &image_infos[2];
write_descriptor_sets[3] = write_descriptor_sets[2];
write_descriptor_sets[3].dstBinding = 1;
write_descriptor_sets[3].pImageInfo = &image_infos[3];
write_descriptor_sets[4] = write_descriptor_sets[0];
write_descriptor_sets[4].dstSet =
view_creator_avc->vk_descriptor_set_sources;
write_descriptor_sets[4].dstBinding = 0;
write_descriptor_sets[4].descriptorType =
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write_descriptor_sets[4].pImageInfo = &image_infos[4];
write_descriptor_sets[5] = write_descriptor_sets[4];
write_descriptor_sets[5].dstBinding = 1;
write_descriptor_sets[5].pImageInfo = &image_infos[5];
vkUpdateDescriptorSets (vk_device, 6, write_descriptor_sets, 0, NULL);
}
static void
maybe_init_image_layout (GrdRdpViewCreatorAVC *view_creator_avc,
VkCommandBuffer command_buffer,
GrdVkImage *image,
VkImageLayout new_layout,
VkAccessFlags2 dst_access_mask)
{
GrdVkDevice *device = view_creator_avc->device;
GrdVkDeviceFuncs *device_funcs = grd_vk_device_get_device_funcs (device);
VkDependencyInfo dependency_info = {};
VkImageMemoryBarrier2 image_memory_barrier_2 = {};
g_assert (device_funcs->vkCmdPipelineBarrier2KHR);
if (grd_vk_image_get_image_layout (image) == new_layout)
return;
image_memory_barrier_2.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2;
image_memory_barrier_2.srcStageMask = VK_PIPELINE_STAGE_2_NONE;
image_memory_barrier_2.srcAccessMask = VK_ACCESS_2_NONE;
image_memory_barrier_2.dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
image_memory_barrier_2.dstAccessMask = dst_access_mask;
image_memory_barrier_2.oldLayout = grd_vk_image_get_image_layout (image);
image_memory_barrier_2.newLayout = new_layout;
image_memory_barrier_2.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier_2.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier_2.image = grd_vk_image_get_image (image);
image_memory_barrier_2.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
image_memory_barrier_2.subresourceRange.baseMipLevel = 0;
image_memory_barrier_2.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
image_memory_barrier_2.subresourceRange.baseArrayLayer = 0;
image_memory_barrier_2.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
dependency_info.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO;
dependency_info.imageMemoryBarrierCount = 1;
dependency_info.pImageMemoryBarriers = &image_memory_barrier_2;
device_funcs->vkCmdPipelineBarrier2KHR (command_buffer, &dependency_info);
}
static gboolean
maybe_record_init_layouts (GrdRdpViewCreatorAVC *view_creator_avc,
GrdImageViewNV12 *main_image_view,
GrdImageViewNV12 *aux_image_view,
GrdVkImage *src_image_new,
GrdVkImage *src_image_old,
GError **error)
{
VkCommandBuffer command_buffer =
view_creator_avc->command_buffers.init_layouts;
VkCommandBufferBeginInfo begin_info = {};
VkResult vk_result;
g_autoptr (GList) images = NULL;
GList *l;
view_creator_avc->pending_layout_transition =
grd_image_view_nv12_get_image_layout (main_image_view) != VK_IMAGE_LAYOUT_GENERAL ||
grd_image_view_nv12_get_image_layout (aux_image_view) != VK_IMAGE_LAYOUT_GENERAL ||
grd_vk_image_get_image_layout (src_image_new) != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ||
(src_image_old &&
grd_vk_image_get_image_layout (src_image_old) != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
if (!view_creator_avc->pending_layout_transition)
return TRUE;
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
vk_result = vkBeginCommandBuffer (command_buffer, &begin_info);
if (vk_result != VK_SUCCESS)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to begin command buffer: %i", vk_result);
return FALSE;
}
images = grd_image_view_nv12_get_images (main_image_view);
images = g_list_concat (images,
grd_image_view_nv12_get_images (aux_image_view));
for (l = images; l; l = l->next)
{
GrdVkImage *image = l->data;
maybe_init_image_layout (view_creator_avc, command_buffer, image,
VK_IMAGE_LAYOUT_GENERAL,
VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT);
}
maybe_init_image_layout (view_creator_avc, command_buffer, src_image_new,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_ACCESS_2_SHADER_STORAGE_READ_BIT);
if (src_image_old)
{
maybe_init_image_layout (view_creator_avc, command_buffer, src_image_old,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_ACCESS_2_SHADER_STORAGE_READ_BIT);
}
vk_result = vkEndCommandBuffer (command_buffer);
if (vk_result != VK_SUCCESS)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to end command buffer: %i", vk_result);
return FALSE;
}
return TRUE;
}
static gboolean
record_create_view (GrdRdpViewCreatorAVC *view_creator_avc,
VkCommandBuffer command_buffer,
Pipeline *pipeline,
GError **error)
{
GrdVkDevice *device = view_creator_avc->device;
GrdVkDeviceFuncs *device_funcs = grd_vk_device_get_device_funcs (device);
ViewCreateInfo *view_create_info = &view_creator_avc->view_create_info;
VkCommandBufferBeginInfo begin_info = {};
VkDescriptorSet descriptor_sets[4] = {};
uint32_t n_groups_x;
uint32_t n_groups_y;
VkResult vk_result;
g_assert (device_funcs->vkCmdWriteTimestamp2KHR);
g_assert (view_create_info->target_width % 16 == 0);
g_assert (view_create_info->target_height % 16 == 0);
g_assert (view_create_info->target_width > 0);
g_assert (view_create_info->target_height > 0);
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
vk_result = vkBeginCommandBuffer (command_buffer, &begin_info);
if (vk_result != VK_SUCCESS)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to begin command buffer: %i", vk_result);
return FALSE;
}
vkCmdResetQueryPool (command_buffer,
view_creator_avc->vk_timestamp_query_pool, 0, 2);
device_funcs->vkCmdWriteTimestamp2KHR (command_buffer,
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
view_creator_avc->vk_timestamp_query_pool,
0);
descriptor_sets[0] = view_creator_avc->vk_descriptor_set_main_view;
descriptor_sets[1] = view_creator_avc->vk_descriptor_set_aux_view;
descriptor_sets[2] = view_creator_avc->vk_descriptor_set_state;
descriptor_sets[3] = view_creator_avc->vk_descriptor_set_sources;
vkCmdBindPipeline (command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE,
pipeline->vk_pipeline);
vkCmdBindDescriptorSets (command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE,
pipeline->vk_pipeline_layout,
0, 4, descriptor_sets, 0, NULL);
n_groups_x = view_create_info->target_width / 2 / 16 +
(view_create_info->target_width / 2 % 16 ? 1 : 0);
n_groups_y = view_create_info->target_height / 2 / 16 +
(view_create_info->target_height / 2 % 16 ? 1 : 0);
vkCmdDispatch (command_buffer, n_groups_x, n_groups_y, 1);
device_funcs->vkCmdWriteTimestamp2KHR (command_buffer,
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
view_creator_avc->vk_timestamp_query_pool,
1);
vk_result = vkEndCommandBuffer (command_buffer);
if (vk_result != VK_SUCCESS)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to end command buffer: %i", vk_result);
return FALSE;
}
return TRUE;
}
static gboolean
record_create_view_command_buffers (GrdRdpViewCreatorAVC *view_creator_avc,
gboolean record_create_simple_view,
gboolean record_create_difference_view,
GError **error)
{
CommandBuffers *command_buffers = &view_creator_avc->command_buffers;
if (record_create_simple_view &&
!record_create_view (view_creator_avc,
command_buffers->create_dual_view_simple,
view_creator_avc->dual_view_pipeline,
error))
return FALSE;
if (record_create_difference_view &&
!record_create_view (view_creator_avc,
command_buffers->create_dual_view_difference,
view_creator_avc->dual_view_dmg_pipeline,
error))
return FALSE;
return TRUE;
}
static gboolean
record_command_buffers (GrdRdpViewCreatorAVC *view_creator_avc,
GrdImageViewNV12 *main_image_view,
GrdImageViewNV12 *aux_image_view,
GrdVkImage *src_image_new,
GrdVkImage *src_image_old,
GError **error)
{
if (!maybe_record_init_layouts (view_creator_avc,
main_image_view, aux_image_view,
src_image_new, src_image_old, error))
return FALSE;
if (view_creator_avc->pending_view_creation_recording &&
!record_create_view_command_buffers (view_creator_avc,
!src_image_old, !!src_image_old,
error))
return FALSE;
return TRUE;
}
static void
update_image_layout_states (GrdImageViewNV12 *main_image_view,
GrdImageViewNV12 *aux_image_view,
GrdVkImage *src_image_new,
GrdVkImage *src_image_old)
{
grd_image_view_nv12_set_image_layout (main_image_view,
VK_IMAGE_LAYOUT_GENERAL);
grd_image_view_nv12_set_image_layout (aux_image_view,
VK_IMAGE_LAYOUT_GENERAL);
grd_vk_image_set_image_layout (src_image_new,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
if (src_image_old)
{
grd_vk_image_set_image_layout (src_image_old,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
}
static gboolean
grd_rdp_view_creator_avc_create_view (GrdRdpViewCreator *view_creator,
GList *image_views,
GrdRdpBuffer *src_buffer_new,
GrdRdpBuffer *src_buffer_old,
GError **error)
{
GrdRdpViewCreatorAVC *view_creator_avc =
GRD_RDP_VIEW_CREATOR_AVC (view_creator);
VkDevice vk_device = grd_vk_device_get_device (view_creator_avc->device);
CommandBuffers *command_buffers = &view_creator_avc->command_buffers;
GrdVkImage *src_image_new = NULL;
GrdVkImage *src_image_old = NULL;
VkCommandBufferSubmitInfo buffer_submit_infos[4] = {};
VkCommandBuffer create_dual_view = VK_NULL_HANDLE;
uint32_t n_buffer_submit_infos = 0;
VkSubmitInfo2 submit_info_2 = {};
GrdImageViewNV12 *main_image_view;
GrdImageViewNV12 *aux_image_view;
VkResult vk_result;
g_assert (image_views);
g_assert (image_views->next);
main_image_view = GRD_IMAGE_VIEW_NV12 (image_views->data);
aux_image_view = GRD_IMAGE_VIEW_NV12 (image_views->next->data);
src_image_new = grd_rdp_buffer_get_dma_buf_image (src_buffer_new);
if (src_buffer_old)
src_image_old = grd_rdp_buffer_get_dma_buf_image (src_buffer_old);
write_image_descriptor_sets (view_creator_avc,
main_image_view, aux_image_view,
src_image_new, src_image_old);
if (!record_command_buffers (view_creator_avc,
main_image_view, aux_image_view,
src_image_new, src_image_old, error))
return FALSE;
vk_result = vkResetFences (vk_device, 1, &view_creator_avc->vk_fence);
if (vk_result != VK_SUCCESS)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to reset fence: %i", vk_result);
return FALSE;
}
if (view_creator_avc->pending_layout_transition)
{
buffer_submit_infos[n_buffer_submit_infos].sType =
VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO;
buffer_submit_infos[n_buffer_submit_infos].commandBuffer =
command_buffers->init_layouts;
++n_buffer_submit_infos;
}
buffer_submit_infos[n_buffer_submit_infos].sType =
VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO;
buffer_submit_infos[n_buffer_submit_infos].commandBuffer =
command_buffers->init_state_buffers;
++n_buffer_submit_infos;
if (src_image_old)
create_dual_view = command_buffers->create_dual_view_difference;
else
create_dual_view = command_buffers->create_dual_view_simple;
buffer_submit_infos[n_buffer_submit_infos].sType =
VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO;
buffer_submit_infos[n_buffer_submit_infos].commandBuffer = create_dual_view;
++n_buffer_submit_infos;
buffer_submit_infos[n_buffer_submit_infos].sType =
VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO;
buffer_submit_infos[n_buffer_submit_infos].commandBuffer =
command_buffers->synchronize_state_buffers;
++n_buffer_submit_infos;
submit_info_2.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2;
submit_info_2.commandBufferInfoCount = n_buffer_submit_infos;
submit_info_2.pCommandBufferInfos = buffer_submit_infos;
if (!grd_vk_queue_submit (view_creator_avc->queue, &submit_info_2, 1,
view_creator_avc->vk_fence, error))
return FALSE;
update_image_layout_states (main_image_view, aux_image_view,
src_image_new, src_image_old);
return TRUE;
}
static gboolean
print_view_creation_time (GrdRdpViewCreatorAVC *view_creator_avc,
GError **error)
{
VkDevice vk_device = grd_vk_device_get_device (view_creator_avc->device);
float timestamp_period =
grd_vk_device_get_timestamp_period (view_creator_avc->device);
uint64_t gpu_timestamps[2] = {};
VkQueryResultFlags query_flags;
float execution_time_us;
VkResult vk_result;
query_flags = VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT;
vk_result = vkGetQueryPoolResults (vk_device,
view_creator_avc->vk_timestamp_query_pool,
0, 2,
sizeof (gpu_timestamps), gpu_timestamps,
sizeof (uint64_t), query_flags);
if (vk_result != VK_SUCCESS)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to get query pool results: %i", vk_result);
return FALSE;
}
execution_time_us = (gpu_timestamps[1] - gpu_timestamps[0]) *
timestamp_period / 1000;
g_debug ("[HWAccel.Vulkan] CreateView[ExecutionTime]: %liµs",
(int64_t) execution_time_us);
return TRUE;
}
static GrdRdpRenderState *
grd_rdp_view_creator_avc_finish_view (GrdRdpViewCreator *view_creator,
GError **error)
{
GrdRdpViewCreatorAVC *view_creator_avc =
GRD_RDP_VIEW_CREATOR_AVC (view_creator);
VkDevice vk_device = grd_vk_device_get_device (view_creator_avc->device);
uint32_t state_buffer_length;
VkResult vk_result;
do
{
vk_result = vkWaitForFences (vk_device, 1, &view_creator_avc->vk_fence,
VK_FALSE, 100 * 1000);
}
while (vk_result == VK_TIMEOUT);
if (vk_result != VK_SUCCESS)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to wait for fence: %i", vk_result);
return NULL;
}
if (view_creator_avc->debug_vk_times &&
!print_view_creation_time (view_creator_avc, error))
return NULL;
state_buffer_length = view_creator_avc->state_buffer_size /
sizeof (uint32_t);
return grd_rdp_render_state_new (view_creator_avc->mapped_dmg_buffer,
view_creator_avc->mapped_chroma_check_buffer,
state_buffer_length);
}
static void
prepare_view_create_info (GrdRdpViewCreatorAVC *view_creator_avc,
uint32_t target_width,
uint32_t target_height,
uint32_t source_width,
uint32_t source_height)
{
ViewCreateInfo *view_create_info = &view_creator_avc->view_create_info;
g_assert (target_width % 16 == 0);
g_assert (target_height % 16 == 0);
g_assert (target_width > 0);
g_assert (target_height > 0);
view_create_info->source_width = source_width;
view_create_info->source_height = source_height;
view_create_info->target_width = target_width;
view_create_info->target_height = target_height;
view_create_info->state_buffer_stride =
grd_get_aligned_size (source_width, 64) / 64;
}
static gboolean
create_state_buffer (GrdRdpViewCreatorAVC *view_creator_avc,
GrdVkBuffer **state_buffer_device,
GrdVkBuffer **state_buffer_host,
uint32_t **mapped_state_buffer,
GError **error)
{
GrdVkBufferDescriptor buffer_descriptor = {};
VkMemoryPropertyFlagBits memory_flags;
GrdVkMemory *memory;
buffer_descriptor.usage_flags = VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
buffer_descriptor.size = view_creator_avc->state_buffer_size;
buffer_descriptor.memory_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
*state_buffer_host = grd_vk_buffer_new (view_creator_avc->device,
&buffer_descriptor,
error);
if (!(*state_buffer_host))
return FALSE;
memory = grd_vk_buffer_get_memory (*state_buffer_host);
*mapped_state_buffer = grd_vk_memory_get_mapped_pointer (memory, error);
if (!(*mapped_state_buffer))
return FALSE;
memory_flags = grd_vk_memory_get_memory_flags (memory);
if (memory_flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
return TRUE;
buffer_descriptor.usage_flags |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
buffer_descriptor.memory_flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
*state_buffer_device = grd_vk_buffer_new (view_creator_avc->device,
&buffer_descriptor,
error);
if (!(*state_buffer_device))
return FALSE;
return TRUE;
}
static gboolean
create_state_buffers (GrdRdpViewCreatorAVC *view_creator_avc,
uint32_t source_width,
uint32_t source_height,
GError **error)
{
view_creator_avc->state_buffer_size =
(grd_get_aligned_size (source_width, 64) / 64) *
(grd_get_aligned_size (source_height, 64) / 64) *
sizeof (uint32_t);
if (!create_state_buffer (view_creator_avc,
&view_creator_avc->dmg_buffer_device,
&view_creator_avc->dmg_buffer_host,
&view_creator_avc->mapped_dmg_buffer,
error))
return FALSE;
if (!create_state_buffer (view_creator_avc,
&view_creator_avc->chroma_check_buffer_device,
&view_creator_avc->chroma_check_buffer_host,
&view_creator_avc->mapped_chroma_check_buffer,
error))
return FALSE;
return TRUE;
}
static gboolean
create_sampler (GrdRdpViewCreatorAVC *view_creator_avc,
VkSampler *sampler,
GError **error)
{
VkDevice vk_device = grd_vk_device_get_device (view_creator_avc->device);
VkSamplerCreateInfo sampler_create_info = {};
VkResult vk_result;
g_assert (sampler);
sampler_create_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
sampler_create_info.magFilter = VK_FILTER_NEAREST;
sampler_create_info.minFilter = VK_FILTER_NEAREST;
sampler_create_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
sampler_create_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
sampler_create_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
sampler_create_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
sampler_create_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
sampler_create_info.unnormalizedCoordinates = VK_TRUE;
vk_result = vkCreateSampler (vk_device, &sampler_create_info, NULL, sampler);
if (vk_result != VK_SUCCESS)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to create sampler: %i", vk_result);
return FALSE;
}
g_assert (*sampler != VK_NULL_HANDLE);
return TRUE;
}
static gboolean
create_samplers (GrdRdpViewCreatorAVC *view_creator_avc,
GError **error)
{
if (!create_sampler (view_creator_avc,
&view_creator_avc->vk_src_new_sampler,
error))
return FALSE;
if (!create_sampler (view_creator_avc,
&view_creator_avc->vk_src_old_sampler,
error))
return FALSE;
return TRUE;
}
static gboolean
create_descriptor_set_layout (GrdRdpViewCreatorAVC *view_creator_avc,
VkDescriptorSetLayout *descriptor_set_layout,
VkDescriptorType descriptor_type,
GError **error)
{
VkDevice vk_device = grd_vk_device_get_device (view_creator_avc->device);
VkDescriptorSetLayoutCreateInfo layout_create_info = {};
VkDescriptorSetLayoutBinding layout_bindings[2] = {};
VkDescriptorSetLayoutBindingFlagsCreateInfo layout_binding_flags_info = {};
VkDescriptorBindingFlags binding_flags[2] = {};
VkResult vk_result;
g_assert (descriptor_set_layout);
layout_bindings[0].binding = 0;
layout_bindings[0].descriptorType = descriptor_type;
layout_bindings[0].descriptorCount = 1;
layout_bindings[0].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
layout_bindings[1] = layout_bindings[0];
layout_bindings[1].binding = 1;
layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layout_create_info.bindingCount = 2;
layout_create_info.pBindings = layout_bindings;
binding_flags[0] = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT;
binding_flags[1] = binding_flags[0];
layout_binding_flags_info.sType =
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO;
layout_binding_flags_info.bindingCount = 2;
layout_binding_flags_info.pBindingFlags = binding_flags;
if (view_creator_avc->supports_update_after_bind &&
descriptor_type != VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
{
layout_create_info.flags =
VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT;
grd_vk_append_to_chain (&layout_create_info, &layout_binding_flags_info);
}
vk_result = vkCreateDescriptorSetLayout (vk_device, &layout_create_info, NULL,
descriptor_set_layout);
if (vk_result != VK_SUCCESS)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to create descriptor set layout: %i", vk_result);
return FALSE;
}
g_assert (*descriptor_set_layout != VK_NULL_HANDLE);
return TRUE;
}
static gboolean
create_descriptor_set_layouts (GrdRdpViewCreatorAVC *view_creator_avc,
GError **error)
{
VkDescriptorSetLayout *target_descriptor_set_layout =
&view_creator_avc->vk_target_descriptor_set_layout;
VkDescriptorSetLayout *source_descriptor_set_layout =
&view_creator_avc->vk_source_descriptor_set_layout;
VkDescriptorSetLayout *state_descriptor_set_layout =
&view_creator_avc->vk_state_descriptor_set_layout;
if (!create_descriptor_set_layout (view_creator_avc,
target_descriptor_set_layout,
VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
error))
return FALSE;
if (!create_descriptor_set_layout (view_creator_avc,
source_descriptor_set_layout,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
error))
return FALSE;
if (!create_descriptor_set_layout (view_creator_avc,
state_descriptor_set_layout,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
error))
return FALSE;
return TRUE;
}
static gboolean
create_image_descriptor_sets (GrdRdpViewCreatorAVC *view_creator_avc,
GError **error)
{
VkDevice vk_device = grd_vk_device_get_device (view_creator_avc->device);
VkDescriptorPoolCreateInfo pool_create_info = {};
VkDescriptorPoolSize pool_sizes[2] = {};
VkDescriptorSetAllocateInfo allocate_info = {};
VkDescriptorSetLayout descriptor_set_layouts[3] = {};
VkDescriptorSet descriptor_sets[3] = {};
VkResult vk_result;
pool_sizes[0].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
pool_sizes[0].descriptorCount = 4;
pool_sizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
pool_sizes[1].descriptorCount = 2;
pool_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
pool_create_info.maxSets = 3;
pool_create_info.poolSizeCount = 2;
pool_create_info.pPoolSizes = pool_sizes;
if (view_creator_avc->supports_update_after_bind)
pool_create_info.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT;
vk_result = vkCreateDescriptorPool (vk_device, &pool_create_info, NULL,
&view_creator_avc->vk_image_descriptor_pool);
if (vk_result != VK_SUCCESS)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to create descriptor pool: %i", vk_result);
return FALSE;
}
g_assert (view_creator_avc->vk_image_descriptor_pool != VK_NULL_HANDLE);
descriptor_set_layouts[0] = view_creator_avc->vk_target_descriptor_set_layout;
descriptor_set_layouts[1] = view_creator_avc->vk_target_descriptor_set_layout;
descriptor_set_layouts[2] = view_creator_avc->vk_source_descriptor_set_layout;
allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocate_info.descriptorPool = view_creator_avc->vk_image_descriptor_pool;
allocate_info.descriptorSetCount = 3;
allocate_info.pSetLayouts = descriptor_set_layouts;
vk_result = vkAllocateDescriptorSets (vk_device, &allocate_info,
descriptor_sets);
if (vk_result != VK_SUCCESS)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to allocate descriptor sets: %i", vk_result);
return FALSE;
}
g_assert (descriptor_sets[0] != VK_NULL_HANDLE);
g_assert (descriptor_sets[1] != VK_NULL_HANDLE);
g_assert (descriptor_sets[2] != VK_NULL_HANDLE);
view_creator_avc->vk_descriptor_set_main_view = descriptor_sets[0];
view_creator_avc->vk_descriptor_set_aux_view = descriptor_sets[1];
view_creator_avc->vk_descriptor_set_sources = descriptor_sets[2];
return TRUE;
}
static gboolean
create_buffer_descriptor_set (GrdRdpViewCreatorAVC *view_creator_avc,
GError **error)
{
VkDevice vk_device = grd_vk_device_get_device (view_creator_avc->device);
VkDescriptorPoolCreateInfo pool_create_info = {};
VkDescriptorPoolSize pool_size = {};
VkDescriptorSetAllocateInfo allocate_info = {};
VkDescriptorSetLayout descriptor_set_layout;
VkDescriptorSet descriptor_set = VK_NULL_HANDLE;
VkResult vk_result;
pool_size.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
pool_size.descriptorCount = 2;
pool_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
pool_create_info.maxSets = 1;
pool_create_info.poolSizeCount = 1;
pool_create_info.pPoolSizes = &pool_size;
vk_result = vkCreateDescriptorPool (vk_device, &pool_create_info, NULL,
&view_creator_avc->vk_buffer_descriptor_pool);
if (vk_result != VK_SUCCESS)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to create descriptor pool: %i", vk_result);
return FALSE;
}
g_assert (view_creator_avc->vk_buffer_descriptor_pool != VK_NULL_HANDLE);
descriptor_set_layout = view_creator_avc->vk_state_descriptor_set_layout;
allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocate_info.descriptorPool = view_creator_avc->vk_buffer_descriptor_pool;
allocate_info.descriptorSetCount = 1;
allocate_info.pSetLayouts = &descriptor_set_layout;
vk_result = vkAllocateDescriptorSets (vk_device, &allocate_info,
&descriptor_set);
if (vk_result != VK_SUCCESS)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to allocate descriptor sets: %i", vk_result);
return FALSE;
}
g_assert (descriptor_set != VK_NULL_HANDLE);
view_creator_avc->vk_descriptor_set_state = descriptor_set;
return TRUE;
}
static gboolean
create_descriptor_sets (GrdRdpViewCreatorAVC *view_creator_avc,
GError **error)
{
if (!create_image_descriptor_sets (view_creator_avc, error))
return FALSE;
if (!create_buffer_descriptor_set (view_creator_avc, error))
return FALSE;
return TRUE;
}
static gboolean
create_pipeline_layout (GrdRdpViewCreatorAVC *view_creator_avc,
const VkDescriptorSetLayout *descriptor_set_layouts,
const uint32_t n_descriptor_set_layouts,
VkPipelineLayout *vk_pipeline_layout,
GError **error)
{
VkDevice vk_device = grd_vk_device_get_device (view_creator_avc->device);
VkPipelineLayoutCreateInfo pipeline_layout_create_info = {};
VkResult vk_result;
g_assert (vk_pipeline_layout);
pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipeline_layout_create_info.setLayoutCount = n_descriptor_set_layouts;
pipeline_layout_create_info.pSetLayouts = descriptor_set_layouts;
vk_result = vkCreatePipelineLayout (vk_device, &pipeline_layout_create_info,
NULL, vk_pipeline_layout);
if (vk_result != VK_SUCCESS)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to create pipeline layout: %i", vk_result);
return FALSE;
}
g_assert (*vk_pipeline_layout != VK_NULL_HANDLE);
return TRUE;
}
static gboolean
create_pipeline (GrdRdpViewCreatorAVC *view_creator_avc,
VkShaderModule vk_shader_module,
VkPipelineLayout vk_pipeline_layout,
VkPipeline *vk_pipeline,
GError **error)
{
GrdVkDevice *device = view_creator_avc->device;
VkDevice vk_device = grd_vk_device_get_device (device);
VkPipelineCache vk_pipeline_cache = grd_vk_device_get_pipeline_cache (device);
ViewCreateInfo *view_create_info = &view_creator_avc->view_create_info;
VkComputePipelineCreateInfo pipeline_create_info = {};
VkSpecializationInfo specialization_info = {};
VkSpecializationMapEntry map_entries[N_SPECIALIZATION_CONSTANTS] = {};
VkResult vk_result;
uint32_t i;
g_assert (vk_shader_module != VK_NULL_HANDLE);
g_assert (vk_pipeline);
g_assert (sizeof (ViewCreateInfo) /
sizeof (uint32_t) == N_SPECIALIZATION_CONSTANTS);
for (i = 0; i < N_SPECIALIZATION_CONSTANTS; ++i)
{
map_entries[i].constantID = i;
map_entries[i].offset = i * sizeof (uint32_t);
map_entries[i].size = sizeof (uint32_t);
}
specialization_info.mapEntryCount = N_SPECIALIZATION_CONSTANTS;
specialization_info.pMapEntries = map_entries;
specialization_info.dataSize = sizeof (ViewCreateInfo);
specialization_info.pData = view_create_info;
pipeline_create_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
pipeline_create_info.stage.sType =
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
pipeline_create_info.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT;
pipeline_create_info.stage.module = vk_shader_module;
pipeline_create_info.stage.pName = "main";
pipeline_create_info.stage.pSpecializationInfo = &specialization_info;
pipeline_create_info.layout = vk_pipeline_layout;
vk_result = vkCreateComputePipelines (vk_device, vk_pipeline_cache,
1, &pipeline_create_info,
NULL, vk_pipeline);
if (vk_result != VK_SUCCESS)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to create compute pipeline: %i", vk_result);
return FALSE;
}
g_assert (*vk_pipeline != VK_NULL_HANDLE);
return TRUE;
}
static Pipeline *
dual_view_pipeline_new (GrdRdpViewCreatorAVC *view_creator_avc,
gboolean perform_dmg_detection,
GError **error)
{
ViewCreateInfo *view_create_info = &view_creator_avc->view_create_info;
const GrdVkShaderModules *shader_modules =
grd_vk_device_get_shader_modules (view_creator_avc->device);
g_autoptr (Pipeline) dual_view_pipeline = NULL;
VkDescriptorSetLayout descriptor_set_layouts[4] = {};
dual_view_pipeline = g_new0 (Pipeline, 1);
dual_view_pipeline->view_creator_avc = view_creator_avc;
descriptor_set_layouts[0] = view_creator_avc->vk_target_descriptor_set_layout;
descriptor_set_layouts[1] = view_creator_avc->vk_target_descriptor_set_layout;
descriptor_set_layouts[2] = view_creator_avc->vk_state_descriptor_set_layout;
descriptor_set_layouts[3] = view_creator_avc->vk_source_descriptor_set_layout;
if (!create_pipeline_layout (view_creator_avc, descriptor_set_layouts, 4,
&dual_view_pipeline->vk_pipeline_layout, error))
return NULL;
view_create_info->perform_dmg_detection = perform_dmg_detection;
if (!create_pipeline (view_creator_avc, shader_modules->create_avc_dual_view,
dual_view_pipeline->vk_pipeline_layout,
&dual_view_pipeline->vk_pipeline, error))
return NULL;
return g_steal_pointer (&dual_view_pipeline);
}
static gboolean
create_pipelines (GrdRdpViewCreatorAVC *view_creator_avc,
GError **error)
{
view_creator_avc->dual_view_pipeline =
dual_view_pipeline_new (view_creator_avc, FALSE, error);
if (!view_creator_avc->dual_view_pipeline)
return FALSE;
view_creator_avc->dual_view_dmg_pipeline =
dual_view_pipeline_new (view_creator_avc, TRUE, error);
if (!view_creator_avc->dual_view_dmg_pipeline)
return FALSE;
return TRUE;
}
static gboolean
create_timestamp_query_pool (GrdRdpViewCreatorAVC *view_creator_avc,
GError **error)
{
VkDevice vk_device = grd_vk_device_get_device (view_creator_avc->device);
VkQueryPoolCreateInfo pool_create_info = {};
VkResult vk_result;
pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
pool_create_info.queryType = VK_QUERY_TYPE_TIMESTAMP;
pool_create_info.queryCount = 2;
vk_result = vkCreateQueryPool (vk_device, &pool_create_info, NULL,
&view_creator_avc->vk_timestamp_query_pool);
if (vk_result != VK_SUCCESS)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to create query pool: %i", vk_result);
return FALSE;
}
g_assert (view_creator_avc->vk_timestamp_query_pool != VK_NULL_HANDLE);
return TRUE;
}
static gboolean
create_command_buffers (GrdRdpViewCreatorAVC *view_creator_avc,
GError **error)
{
VkDevice vk_device = grd_vk_device_get_device (view_creator_avc->device);
CommandBuffers *command_buffers = &view_creator_avc->command_buffers;
GrdVkQueue *queue = view_creator_avc->queue;
VkCommandPoolCreateInfo pool_create_info = {};
VkCommandBufferAllocateInfo allocate_info = {};
VkCommandBuffer vk_command_buffers[5] = {};
VkResult vk_result;
pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
pool_create_info.queueFamilyIndex = grd_vk_queue_get_queue_family_idx (queue);
vk_result = vkCreateCommandPool (vk_device, &pool_create_info, NULL,
&view_creator_avc->vk_command_pool);
if (vk_result != VK_SUCCESS)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to create command pool: %i", vk_result);
return FALSE;
}
g_assert (view_creator_avc->vk_command_pool != VK_NULL_HANDLE);
allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocate_info.commandPool = view_creator_avc->vk_command_pool;
allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocate_info.commandBufferCount = 5;
vk_result = vkAllocateCommandBuffers (vk_device, &allocate_info,
vk_command_buffers);
if (vk_result != VK_SUCCESS)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to allocate command buffers: %i", vk_result);
return FALSE;
}
g_assert (vk_command_buffers[0] != VK_NULL_HANDLE);
g_assert (vk_command_buffers[1] != VK_NULL_HANDLE);
g_assert (vk_command_buffers[2] != VK_NULL_HANDLE);
g_assert (vk_command_buffers[3] != VK_NULL_HANDLE);
g_assert (vk_command_buffers[4] != VK_NULL_HANDLE);
command_buffers->init_state_buffers = vk_command_buffers[0];
command_buffers->synchronize_state_buffers = vk_command_buffers[1];
command_buffers->init_layouts = vk_command_buffers[2];
command_buffers->create_dual_view_simple = vk_command_buffers[3];
command_buffers->create_dual_view_difference = vk_command_buffers[4];
return TRUE;
}
static gboolean
create_fence (GrdRdpViewCreatorAVC *view_creator_avc,
GError **error)
{
VkDevice vk_device = grd_vk_device_get_device (view_creator_avc->device);
VkFenceCreateInfo fence_create_info = {};
VkResult vk_result;
fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
vk_result = vkCreateFence (vk_device, &fence_create_info, NULL,
&view_creator_avc->vk_fence);
if (vk_result != VK_SUCCESS)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to create fence: %i", vk_result);
return FALSE;
}
g_assert (view_creator_avc->vk_fence != VK_NULL_HANDLE);
return TRUE;
}
static void
write_state_descriptor_set (GrdRdpViewCreatorAVC *view_creator_avc)
{
VkDevice vk_device = grd_vk_device_get_device (view_creator_avc->device);
VkWriteDescriptorSet write_descriptor_sets[2] = {};
VkDescriptorBufferInfo buffer_infos[2] = {};
GrdVkBuffer *dmg_buffer;
GrdVkBuffer *chroma_check_buffer;
dmg_buffer = view_creator_avc->dmg_buffer_device;
if (!dmg_buffer)
dmg_buffer = view_creator_avc->dmg_buffer_host;
chroma_check_buffer = view_creator_avc->chroma_check_buffer_device;
if (!chroma_check_buffer)
chroma_check_buffer = view_creator_avc->chroma_check_buffer_host;
buffer_infos[0].buffer = grd_vk_buffer_get_buffer (dmg_buffer);
buffer_infos[0].offset = 0;
buffer_infos[0].range = VK_WHOLE_SIZE;
buffer_infos[1] = buffer_infos[0];
buffer_infos[1].buffer = grd_vk_buffer_get_buffer (chroma_check_buffer);
write_descriptor_sets[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write_descriptor_sets[0].dstSet = view_creator_avc->vk_descriptor_set_state;
write_descriptor_sets[0].dstBinding = 0;
write_descriptor_sets[0].descriptorCount = 1;
write_descriptor_sets[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
write_descriptor_sets[0].pBufferInfo = &buffer_infos[0];
write_descriptor_sets[1] = write_descriptor_sets[0];
write_descriptor_sets[1].dstBinding = 1;
write_descriptor_sets[1].pBufferInfo = &buffer_infos[1];
vkUpdateDescriptorSets (vk_device, 2, write_descriptor_sets, 0, NULL);
}
static gboolean
record_init_state_buffers (GrdRdpViewCreatorAVC *view_creator_avc,
GError **error)
{
CommandBuffers *command_buffers = &view_creator_avc->command_buffers;
VkCommandBuffer command_buffer = command_buffers->init_state_buffers;
GrdVkDevice *device = view_creator_avc->device;
GrdVkDeviceFuncs *device_funcs = grd_vk_device_get_device_funcs (device);
VkCommandBufferBeginInfo begin_info = {};
VkDependencyInfo dependency_info = {};
VkMemoryBarrier2 memory_barrier_2 = {};
GrdVkBuffer *dmg_buffer;
GrdVkBuffer *chroma_check_buffer;
VkResult vk_result;
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
vk_result = vkBeginCommandBuffer (command_buffer, &begin_info);
if (vk_result != VK_SUCCESS)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to begin command buffer: %i", vk_result);
return FALSE;
}
dmg_buffer = view_creator_avc->dmg_buffer_device;
if (!dmg_buffer)
dmg_buffer = view_creator_avc->dmg_buffer_host;
chroma_check_buffer = view_creator_avc->chroma_check_buffer_device;
if (!chroma_check_buffer)
chroma_check_buffer = view_creator_avc->chroma_check_buffer_host;
vkCmdFillBuffer (command_buffer,
grd_vk_buffer_get_buffer (dmg_buffer),
0, VK_WHOLE_SIZE,
0);
vkCmdFillBuffer (command_buffer,
grd_vk_buffer_get_buffer (chroma_check_buffer),
0, VK_WHOLE_SIZE,
0);
memory_barrier_2.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2;
memory_barrier_2.srcStageMask = VK_PIPELINE_STAGE_2_CLEAR_BIT;
memory_barrier_2.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT;
memory_barrier_2.dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
memory_barrier_2.dstAccessMask = VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT;
dependency_info.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO;
dependency_info.memoryBarrierCount = 1;
dependency_info.pMemoryBarriers = &memory_barrier_2;
device_funcs->vkCmdPipelineBarrier2KHR (command_buffer, &dependency_info);
vk_result = vkEndCommandBuffer (command_buffer);
if (vk_result != VK_SUCCESS)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to end command buffer: %i", vk_result);
return FALSE;
}
return TRUE;
}
static gboolean
have_device_state_buffers (GrdRdpViewCreatorAVC *view_creator_avc)
{
gboolean have_device_state_buffers;
have_device_state_buffers = view_creator_avc->dmg_buffer_device ||
view_creator_avc->chroma_check_buffer_device;
if (have_device_state_buffers)
{
g_assert (view_creator_avc->dmg_buffer_device &&
view_creator_avc->chroma_check_buffer_device);
}
return have_device_state_buffers;
}
static void
record_synchronize_device_state_buffers (GrdRdpViewCreatorAVC *view_creator_avc,
VkCommandBuffer command_buffer)
{
GrdVkDevice *device = view_creator_avc->device;
GrdVkDeviceFuncs *device_funcs = grd_vk_device_get_device_funcs (device);
GrdVkBuffer *dmg_buffer_device = view_creator_avc->dmg_buffer_device;
GrdVkBuffer *dmg_buffer_host = view_creator_avc->dmg_buffer_host;
GrdVkBuffer *chroma_check_buffer_device =
view_creator_avc->chroma_check_buffer_device;
GrdVkBuffer *chroma_check_buffer_host =
view_creator_avc->chroma_check_buffer_host;
VkDependencyInfo dependency_info = {};
VkMemoryBarrier2 memory_barrier_2 = {};
VkBufferCopy buffer_copy = {};
memory_barrier_2.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2;
memory_barrier_2.srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
memory_barrier_2.srcAccessMask = VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT;
memory_barrier_2.dstStageMask = VK_PIPELINE_STAGE_2_COPY_BIT;
memory_barrier_2.dstAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT;
dependency_info.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO;
dependency_info.memoryBarrierCount = 1;
dependency_info.pMemoryBarriers = &memory_barrier_2;
device_funcs->vkCmdPipelineBarrier2KHR (command_buffer, &dependency_info);
buffer_copy.srcOffset = 0;
buffer_copy.dstOffset = 0;
buffer_copy.size = view_creator_avc->state_buffer_size;
vkCmdCopyBuffer (command_buffer,
grd_vk_buffer_get_buffer (dmg_buffer_device),
grd_vk_buffer_get_buffer (dmg_buffer_host),
1, &buffer_copy);
vkCmdCopyBuffer (command_buffer,
grd_vk_buffer_get_buffer (chroma_check_buffer_device),
grd_vk_buffer_get_buffer (chroma_check_buffer_host),
1, &buffer_copy);
memory_barrier_2.srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT;
memory_barrier_2.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT;
memory_barrier_2.dstStageMask = VK_PIPELINE_STAGE_2_HOST_BIT;
memory_barrier_2.dstAccessMask = VK_ACCESS_2_HOST_READ_BIT;
device_funcs->vkCmdPipelineBarrier2KHR (command_buffer, &dependency_info);
}
static void
record_synchronize_host_state_buffers (GrdRdpViewCreatorAVC *view_creator_avc,
VkCommandBuffer command_buffer)
{
GrdVkDevice *device = view_creator_avc->device;
GrdVkDeviceFuncs *device_funcs = grd_vk_device_get_device_funcs (device);
VkDependencyInfo dependency_info = {};
VkMemoryBarrier2 memory_barrier_2 = {};
memory_barrier_2.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2;
memory_barrier_2.srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
memory_barrier_2.srcAccessMask = VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT;
memory_barrier_2.dstStageMask = VK_PIPELINE_STAGE_2_HOST_BIT;
memory_barrier_2.dstAccessMask = VK_ACCESS_2_HOST_READ_BIT;
dependency_info.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO;
dependency_info.memoryBarrierCount = 1;
dependency_info.pMemoryBarriers = &memory_barrier_2;
device_funcs->vkCmdPipelineBarrier2KHR (command_buffer, &dependency_info);
}
static gboolean
record_synchronize_state_buffers (GrdRdpViewCreatorAVC *view_creator_avc,
GError **error)
{
CommandBuffers *command_buffers = &view_creator_avc->command_buffers;
VkCommandBuffer command_buffer = command_buffers->synchronize_state_buffers;
VkCommandBufferBeginInfo begin_info = {};
VkResult vk_result;
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
vk_result = vkBeginCommandBuffer (command_buffer, &begin_info);
if (vk_result != VK_SUCCESS)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to begin command buffer: %i", vk_result);
return FALSE;
}
if (have_device_state_buffers (view_creator_avc))
record_synchronize_device_state_buffers (view_creator_avc, command_buffer);
else
record_synchronize_host_state_buffers (view_creator_avc, command_buffer);
vk_result = vkEndCommandBuffer (command_buffer);
if (vk_result != VK_SUCCESS)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to end command buffer: %i", vk_result);
return FALSE;
}
return TRUE;
}
static gboolean
record_state_handling_command_buffers (GrdRdpViewCreatorAVC *view_creator_avc,
GError **error)
{
if (!record_init_state_buffers (view_creator_avc, error))
return FALSE;
if (!record_synchronize_state_buffers (view_creator_avc, error))
return FALSE;
return TRUE;
}
GrdRdpViewCreatorAVC *
grd_rdp_view_creator_avc_new (GrdVkDevice *device,
uint32_t target_width,
uint32_t target_height,
uint32_t source_width,
uint32_t source_height,
GError **error)
{
g_autoptr (GrdRdpViewCreatorAVC) view_creator_avc = NULL;
GrdVkPhysicalDevice *physical_device =
grd_vk_device_get_physical_device (device);
GrdVkDeviceFeatures device_features =
grd_vk_physical_device_get_device_features (physical_device);
view_creator_avc = g_object_new (GRD_TYPE_RDP_VIEW_CREATOR_AVC, NULL);
view_creator_avc->device = device;
if (device_features & GRD_VK_DEVICE_FEATURE_UPDATE_AFTER_BIND_SAMPLED_IMAGE &&
device_features & GRD_VK_DEVICE_FEATURE_UPDATE_AFTER_BIND_STORAGE_IMAGE)
view_creator_avc->supports_update_after_bind = TRUE;
prepare_view_create_info (view_creator_avc,
target_width, target_height,
source_width, source_height);
if (!create_state_buffers (view_creator_avc,
source_width, source_height,
error))
return NULL;
if (!create_samplers (view_creator_avc, error))
return NULL;
if (!create_descriptor_set_layouts (view_creator_avc, error))
return NULL;
if (!create_descriptor_sets (view_creator_avc, error))
return NULL;
if (!create_pipelines (view_creator_avc, error))
return NULL;
view_creator_avc->queue = grd_vk_device_acquire_queue (device);
if (!create_timestamp_query_pool (view_creator_avc, error))
return NULL;
if (!create_command_buffers (view_creator_avc, error))
return NULL;
if (!create_fence (view_creator_avc, error))
return NULL;
write_state_descriptor_set (view_creator_avc);
if (!record_state_handling_command_buffers (view_creator_avc, error))
return NULL;
if (view_creator_avc->supports_update_after_bind &&
!record_create_view_command_buffers (view_creator_avc, TRUE, TRUE, error))
return NULL;
if (view_creator_avc->supports_update_after_bind)
view_creator_avc->pending_view_creation_recording = FALSE;
return g_steal_pointer (&view_creator_avc);
}
static void
grd_rdp_view_creator_avc_dispose (GObject *object)
{
GrdRdpViewCreatorAVC *view_creator_avc = GRD_RDP_VIEW_CREATOR_AVC (object);
GrdVkDevice *device = view_creator_avc->device;
grd_vk_clear_fence (device, &view_creator_avc->vk_fence);
grd_vk_clear_command_pool (device, &view_creator_avc->vk_command_pool);
grd_vk_clear_query_pool (device, &view_creator_avc->vk_timestamp_query_pool);
if (view_creator_avc->queue)
{
grd_vk_device_release_queue (device, view_creator_avc->queue);
view_creator_avc->queue = NULL;
}
g_clear_pointer (&view_creator_avc->dual_view_dmg_pipeline, pipeline_free);
g_clear_pointer (&view_creator_avc->dual_view_pipeline, pipeline_free);
grd_vk_clear_descriptor_pool (device, &view_creator_avc->vk_buffer_descriptor_pool);
grd_vk_clear_descriptor_pool (device, &view_creator_avc->vk_image_descriptor_pool);
grd_vk_clear_descriptor_set_layout (device,
&view_creator_avc->vk_state_descriptor_set_layout);
grd_vk_clear_descriptor_set_layout (device,
&view_creator_avc->vk_source_descriptor_set_layout);
grd_vk_clear_descriptor_set_layout (device,
&view_creator_avc->vk_target_descriptor_set_layout);
grd_vk_clear_sampler (device, &view_creator_avc->vk_src_old_sampler);
grd_vk_clear_sampler (device, &view_creator_avc->vk_src_new_sampler);
g_clear_object (&view_creator_avc->chroma_check_buffer_device);
g_clear_object (&view_creator_avc->chroma_check_buffer_host);
g_clear_object (&view_creator_avc->dmg_buffer_device);
g_clear_object (&view_creator_avc->dmg_buffer_host);
G_OBJECT_CLASS (grd_rdp_view_creator_avc_parent_class)->dispose (object);
}
static void
grd_rdp_view_creator_avc_init (GrdRdpViewCreatorAVC *view_creator_avc)
{
if (grd_get_debug_flags () & GRD_DEBUG_VK_TIMES)
view_creator_avc->debug_vk_times = TRUE;
view_creator_avc->pending_view_creation_recording = TRUE;
}
static void
grd_rdp_view_creator_avc_class_init (GrdRdpViewCreatorAVCClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GrdRdpViewCreatorClass *view_creator_class =
GRD_RDP_VIEW_CREATOR_CLASS (klass);
object_class->dispose = grd_rdp_view_creator_avc_dispose;
view_creator_class->create_view = grd_rdp_view_creator_avc_create_view;
view_creator_class->finish_view = grd_rdp_view_creator_avc_finish_view;
}