gtk/gsk/gpu/gskgpublitop.c
Benjamin Otte b3d044a0b1 gpu: Add more assertions to blitop
The blitop is nasty, so we should make sure we have supported images
when using it.
2024-01-07 07:22:53 +01:00

224 lines
7.5 KiB
C

#include "config.h"
#include "gskgpublitopprivate.h"
#include "gskglimageprivate.h"
#include "gskgpuprintprivate.h"
#ifdef GDK_RENDERING_VULKAN
#include "gskvulkanimageprivate.h"
#endif
typedef struct _GskGpuBlitOp GskGpuBlitOp;
struct _GskGpuBlitOp
{
GskGpuOp op;
GskGpuImage *src_image;
GskGpuImage *dest_image;
cairo_rectangle_int_t src_rect;
cairo_rectangle_int_t dest_rect;
GskGpuBlitFilter filter;
};
static void
gsk_gpu_blit_op_finish (GskGpuOp *op)
{
GskGpuBlitOp *self = (GskGpuBlitOp *) op;
g_object_unref (self->src_image);
g_object_unref (self->dest_image);
}
static void
gsk_gpu_blit_op_print (GskGpuOp *op,
GskGpuFrame *frame,
GString *string,
guint indent)
{
GskGpuBlitOp *self = (GskGpuBlitOp *) op;
gsk_gpu_print_op (string, indent, "blit");
gsk_gpu_print_int_rect (string, &self->dest_rect);
gsk_gpu_print_newline (string);
}
#ifdef GDK_RENDERING_VULKAN
static GskGpuOp *
gsk_gpu_blit_op_vk_command (GskGpuOp *op,
GskGpuFrame *frame,
GskVulkanCommandState *state)
{
GskGpuBlitOp *self = (GskGpuBlitOp *) op;
VkImageLayout src_layout, dest_layout;
VkFilter filter;
src_layout = gsk_vulkan_image_get_vk_image_layout (GSK_VULKAN_IMAGE (self->src_image));
if (src_layout != VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR &&
src_layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL &&
src_layout != VK_IMAGE_LAYOUT_GENERAL)
{
gsk_vulkan_image_transition (GSK_VULKAN_IMAGE (self->src_image),
state->semaphores,
state->vk_command_buffer,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_ACCESS_TRANSFER_READ_BIT);
src_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
}
dest_layout = gsk_vulkan_image_get_vk_image_layout (GSK_VULKAN_IMAGE (self->dest_image));
if (dest_layout != VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR &&
dest_layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL &&
dest_layout != VK_IMAGE_LAYOUT_GENERAL)
{
gsk_vulkan_image_transition (GSK_VULKAN_IMAGE (self->dest_image),
state->semaphores,
state->vk_command_buffer,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_ACCESS_TRANSFER_WRITE_BIT);
dest_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
}
switch (self->filter)
{
default:
g_assert_not_reached ();
G_GNUC_FALLTHROUGH;
case GSK_GPU_BLIT_LINEAR:
filter = VK_FILTER_LINEAR;
break;
case GSK_GPU_BLIT_NEAREST:
filter = VK_FILTER_NEAREST;
break;
}
vkCmdBlitImage (state->vk_command_buffer,
gsk_vulkan_image_get_vk_image (GSK_VULKAN_IMAGE (self->src_image)),
src_layout,
gsk_vulkan_image_get_vk_image (GSK_VULKAN_IMAGE (self->dest_image)),
dest_layout,
1,
&(VkImageBlit) {
.srcSubresource = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1
},
.srcOffsets = {
{
.x = self->src_rect.x,
.y = self->src_rect.y,
.z = 0,
},
{
.x = self->src_rect.x + self->src_rect.width,
.y = self->src_rect.y + self->src_rect.height,
.z = 1
}
},
.dstSubresource = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1
},
.dstOffsets = {
{
.x = self->dest_rect.x,
.y = self->dest_rect.y,
.z = 0,
},
{
.x = self->dest_rect.x + self->dest_rect.width,
.y = self->dest_rect.y + self->dest_rect.height,
.z = 1,
}
},
},
filter);
return op->next;
}
#endif
static GskGpuOp *
gsk_gpu_blit_op_gl_command (GskGpuOp *op,
GskGpuFrame *frame,
GskGLCommandState *state)
{
GskGpuBlitOp *self = (GskGpuBlitOp *) op;
GLenum filter;
gsk_gl_image_bind_framebuffer_target (GSK_GL_IMAGE (self->src_image), GL_READ_FRAMEBUFFER);
gsk_gl_image_bind_framebuffer_target (GSK_GL_IMAGE (self->dest_image), GL_DRAW_FRAMEBUFFER);
switch (self->filter)
{
default:
g_assert_not_reached ();
G_GNUC_FALLTHROUGH;
case GSK_GPU_BLIT_LINEAR:
filter = GL_LINEAR;
break;
case GSK_GPU_BLIT_NEAREST:
filter = GL_NEAREST;
break;
}
glDisable (GL_SCISSOR_TEST);
glBlitFramebuffer (self->src_rect.x,
self->src_rect.y,
self->src_rect.x + self->src_rect.width,
self->src_rect.y + self->src_rect.height,
self->dest_rect.x,
state->flip_y ? state->flip_y - self->dest_rect.y - self->dest_rect.height
: self->dest_rect.y,
self->dest_rect.x + self->dest_rect.width,
state->flip_y ? state->flip_y - self->dest_rect.y
: self->dest_rect.y + self->dest_rect.height,
GL_COLOR_BUFFER_BIT,
filter);
glEnable (GL_SCISSOR_TEST);
return op->next;
}
static const GskGpuOpClass GSK_GPU_BLIT_OP_CLASS = {
GSK_GPU_OP_SIZE (GskGpuBlitOp),
GSK_GPU_STAGE_PASS,
gsk_gpu_blit_op_finish,
gsk_gpu_blit_op_print,
#ifdef GDK_RENDERING_VULKAN
gsk_gpu_blit_op_vk_command,
#endif
gsk_gpu_blit_op_gl_command
};
void
gsk_gpu_blit_op (GskGpuFrame *frame,
GskGpuImage *src_image,
GskGpuImage *dest_image,
const cairo_rectangle_int_t *src_rect,
const cairo_rectangle_int_t *dest_rect,
GskGpuBlitFilter filter)
{
GskGpuBlitOp *self;
g_assert ((gsk_gpu_image_get_flags (src_image) & GSK_GPU_IMAGE_NO_BLIT) == 0);
g_assert (filter != GSK_GPU_BLIT_LINEAR || (gsk_gpu_image_get_flags (src_image) & GSK_GPU_IMAGE_FILTERABLE) == GSK_GPU_IMAGE_FILTERABLE);
g_assert ((gsk_gpu_image_get_flags (dest_image) & GSK_GPU_IMAGE_RENDERABLE) == GSK_GPU_IMAGE_RENDERABLE);
self = (GskGpuBlitOp *) gsk_gpu_op_alloc (frame, &GSK_GPU_BLIT_OP_CLASS);
self->src_image = g_object_ref (src_image);
self->dest_image = g_object_ref (dest_image);
self->src_rect = *src_rect;
self->dest_rect = *dest_rect;
self->filter = filter;
}