mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-26 21:51:08 +00:00
b3d044a0b1
The blitop is nasty, so we should make sure we have supported images when using it.
224 lines
7.5 KiB
C
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;
|
|
}
|