JBR-8740 Vulkan: Optimize BLIT (Part 4)

Optimized validation of rendering state.
This commit is contained in:
Alexey Ushakov
2025-07-14 16:13:02 +02:00
parent c64580b6c6
commit 1e8527ec03
5 changed files with 128 additions and 242 deletions

View File

@@ -95,149 +95,6 @@ static AlphaType getSrcAlphaType(jshort srctype) {
ALPHA_TYPE_PRE_MULTIPLIED : ALPHA_TYPE_STRAIGHT;
}
static void VKTexturePoolTexture_Dispose(VKDevice* device, void* ctx) {
VKTexturePoolHandle* hnd = (VKTexturePoolHandle*) ctx;
VKTexturePoolHandle_ReleaseTexture(hnd);
}
static void VKBlitSwToTextureViaPooledTexture(VKRenderingContext* context,
VKSDOps *dstOps,
const SurfaceDataRasInfo *srcInfo, jshort srctype, jint hint,
int dx1, int dy1, int dx2, int dy2) {
VKSDOps* surface = context->surface;
VKDevice* device = surface->device;
const int sw = srcInfo->bounds.x2 - srcInfo->bounds.x1;
const int sh = srcInfo->bounds.y2 - srcInfo->bounds.y1;
ARRAY(VKTxVertex) vertices = ARRAY_ALLOC(VKTxVertex, 4);
/*
* (p1)---------(p2)
* | |
* | |
* | |
* (p4)---------(p3)
*/
BlitSrcType type = decodeSrcType(device, srctype);
VKTexturePoolHandle* hnd = VKTexturePool_GetTexture(device->texturePool, sw, sh, type.format);
double u = (double)sw;
double v = (double)sh;
ARRAY_PUSH_BACK(vertices) = (VKTxVertex) {dx1, dy1, 0.0f, 0.0f};
ARRAY_PUSH_BACK(vertices) = (VKTxVertex) {dx2, dy1, u, 0.0f};
ARRAY_PUSH_BACK(vertices) = (VKTxVertex) {dx1, dy2, 0.0f, v};
ARRAY_PUSH_BACK(vertices) = (VKTxVertex) {dx2, dy2, u, v};
VKBuffer* renderVertexBuffer = ARRAY_TO_VERTEX_BUF(device, vertices);
ARRAY_FREE(vertices);
J2dTraceLn4(J2D_TRACE_VERBOSE, "replaceTextureRegion src (dw, dh) : [%d, %d] dest (dx1, dy1) =[%d, %d]",
(dx2 - dx1), (dy2 - dy1), dx1, dy1);
VKBuffer *buffer =
VKBuffer_CreateFromRaster(device, (VKBuffer_RasterInfo){
.data = srcInfo->rasBase,
.x1 = srcInfo->bounds.x1,
.y1 = srcInfo->bounds.y1,
.w = sw,
.h = sh,
.pixelStride = srcInfo->pixelStride,
.scanStride = srcInfo->scanStride
}, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT);
{
VkImageMemoryBarrier barrier;
VKBarrierBatch barrierBatch = {};
VKImage_AddBarrier(&barrier, &barrierBatch, VKTexturePoolHandle_GetTexture(hnd),
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
VKRenderer_RecordBarriers(device->renderer, NULL, NULL, &barrier, &barrierBatch);
}
VKImage_LoadBuffer(context->surface->device,
VKTexturePoolHandle_GetTexture(hnd), buffer, 0, 0, sw, sh);
{
VkImageMemoryBarrier barrier;
VKBarrierBatch barrierBatch = {};
VKImage_AddBarrier(&barrier, &barrierBatch, VKTexturePoolHandle_GetTexture(hnd),
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
VKRenderer_RecordBarriers(device->renderer, NULL, NULL, &barrier, &barrierBatch);
}
VKImage* src = VKTexturePoolHandle_GetTexture(hnd);
VkDescriptorSet srcDescriptorSet = VKImage_GetDescriptorSet(device, src, type.format, type.swizzle);
VKRenderer_TextureRender(srcDescriptorSet, renderVertexBuffer->handle, 4, hint, SAMPLER_WRAP_BORDER);
VKRenderer_FlushSurface(dstOps);
VKRenderer_DisposeOnCleanup(device->renderer, VKTexturePoolTexture_Dispose, hnd);
VKRenderer_DisposeOnCleanup(device->renderer, VKBuffer_Dispose, buffer);
}
static jboolean clipDestCoords(
VKRenderingContext* context,
jdouble *dx1, jdouble *dy1, jdouble *dx2, jdouble *dy2,
jint *sx1, jint *sy1, jint *sx2, jint *sy2,
jint destW, jint destH) {
// Trim destination rect by clip-rect (or dest.bounds)
const jint sw = *sx2 - *sx1;
const jint sh = *sy2 - *sy1;
const jdouble dw = *dx2 - *dx1;
const jdouble dh = *dy2 - *dy1;
VkRect2D* clipRect = &context->clipRect;
jdouble dcx1 = 0;
jdouble dcx2 = destW;
jdouble dcy1 = 0;
jdouble dcy2 = destH;
if (clipRect->offset.x > dcx1)
dcx1 = clipRect->offset.x;
const int maxX = clipRect->offset.x + clipRect->extent.width;
if (dcx2 > maxX)
dcx2 = maxX;
if (clipRect->offset.y > dcy1)
dcy1 = clipRect->offset.y;
const int maxY = clipRect->offset.y + clipRect->extent.height;
if (dcy2 > maxY)
dcy2 = maxY;
if (dcx1 >= dcx2) {
J2dTraceLn2(J2D_TRACE_ERROR, "\tclipDestCoords: dcx1=%1.2f, dcx2=%1.2f", dcx1, dcx2);
dcx1 = dcx2;
}
if (dcy1 >= dcy2) {
J2dTraceLn2(J2D_TRACE_ERROR, "\tclipDestCoords: dcy1=%1.2f, dcy2=%1.2f", dcy1, dcy2);
dcy1 = dcy2;
}
if (*dx2 <= dcx1 || *dx1 >= dcx2 || *dy2 <= dcy1 || *dy1 >= dcy2) {
J2dTraceLn(J2D_TRACE_INFO, "\tclipDestCoords: dest rect doesn't intersect clip area");
J2dTraceLn4(J2D_TRACE_INFO, "\tdx2=%1.4f <= dcx1=%1.4f || *dx1=%1.4f >= dcx2=%1.4f", *dx2, dcx1, *dx1, dcx2);
J2dTraceLn4(J2D_TRACE_INFO, "\t*dy2=%1.4f <= dcy1=%1.4f || *dy1=%1.4f >= dcy2=%1.4f", *dy2, dcy1, *dy1, dcy2);
return JNI_FALSE;
}
if (*dx1 < dcx1) {
J2dTraceLn3(J2D_TRACE_VERBOSE, "\t\tdx1=%1.2f, will be clipped to %1.2f | sx1+=%d", *dx1, dcx1, (jint)((dcx1 - *dx1) * (sw/dw)));
*sx1 += (jint)((dcx1 - *dx1) * (sw/dw));
*dx1 = dcx1;
}
if (*dx2 > dcx2) {
J2dTraceLn3(J2D_TRACE_VERBOSE, "\t\tdx2=%1.2f, will be clipped to %1.2f | sx2-=%d", *dx2, dcx2, (jint)((*dx2 - dcx2) * (sw/dw)));
*sx2 -= (jint)((*dx2 - dcx2) * (sw/dw));
*dx2 = dcx2;
}
if (*dy1 < dcy1) {
J2dTraceLn3(J2D_TRACE_VERBOSE, "\t\tdy1=%1.2f, will be clipped to %1.2f | sy1+=%d", *dy1, dcy1, (jint)((dcy1 - *dy1) * (sh/dh)));
*sy1 += (jint)((dcy1 - *dy1) * (sh/dh));
*dy1 = dcy1;
}
if (*dy2 > dcy2) {
J2dTraceLn3(J2D_TRACE_VERBOSE, "\t\tdy2=%1.2f, will be clipped to %1.2f | sy2-=%d", *dy2, dcy2, (jint)((*dy2 - dcy2) * (sh/dh)));
*sy2 -= (jint)((*dy2 - dcy2) * (sh/dh));
*dy2 = dcy2;
}
return JNI_TRUE;
}
void VKBlitLoops_IsoBlit(VKSDOps* srcOps, jint filter,
jint sx1, jint sy1, jint sx2, jint sy2,
jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
@@ -265,109 +122,134 @@ void VKBlitLoops_IsoBlit(VKSDOps* srcOps, jint filter,
VK_COMPONENT_SWIZZLE_ONE);
VKPackedSwizzle swizzle = srcOpaque ? OPAQUE_SWIZZLE : 0;
VKRenderer_DrawImage(srcOps->image, alphaType, srcOps->image->format, swizzle, filter, SAMPLER_WRAP_BORDER,
if (!VKRenderer_Validate(SHADER_BLIT, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, alphaType)) return;
VKRenderer_DrawImage(srcOps->image, srcOps->image->format, swizzle, filter, SAMPLER_WRAP_BORDER,
(float)sx1, (float)sy1, (float)sx2, (float)sy2, (float)dx1, (float)dy1, (float)dx2, (float)dy2);
VKRenderer_AddSurfaceDependency(srcOps, context->surface);
}
static void VKBlitLoops_DisposeTexture(VKDevice* device, void* data) {
VKTexturePoolHandle_ReleaseTexture(data);
}
static void VKBlitLoops_DisposeBuffer(VKDevice* device, void* data) {
device->vkDestroyBuffer(device->handle, (VkBuffer) data, NULL);
}
static void VKBlitLoops_DisposeMemory(VKDevice* device, void* data) {
VKAllocator_Free(device->allocator, data);
}
static void VKBlitLoops_FindStageBufferMemoryType(VKMemoryRequirements* requirements) {
VKAllocator_FindMemoryType(requirements, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT,
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
VKAllocator_FindMemoryType(requirements, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_ALL_MEMORY_PROPERTIES);
}
void VKBlitLoops_Blit(JNIEnv *env,
jlong pSrcOps, jboolean xform, jint hint,
jshort srctype,
SurfaceDataOps* src,
jshort srctype, jint hint,
jint sx1, jint sy1,
jint sx2, jint sy2,
jdouble dx1, jdouble dy1,
jdouble dx2, jdouble dy2)
{
J2dRlsTraceLn8(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: BLIT_Blit (%d %d %d %d) -> (%f %f %f %f) ",
sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2)
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: BLIT_Blit xform=%d srctype=%d", xform, srctype)
SurfaceDataOps *srcOps = (SurfaceDataOps *)jlong_to_ptr(pSrcOps);
if (srcOps == NULL) {
J2dRlsTraceLn1(J2D_TRACE_ERROR, "VKBlitLoops_Blit: srcOps(%p) is null",
srcOps)
if (src == NULL) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "VKRenderer_Blit: src is null");
return;
}
VKRenderingContext* context = VKRenderer_GetContext();
if (!VKRenderer_Validate(SHADER_BLIT, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, getSrcAlphaType(srctype))) {
J2dTraceLn(J2D_TRACE_INFO, "VKBlitLoops_Blit: VKRenderer_Validate cannot validate renderer");
return;
}
VKRenderingContext *context = VKRenderer_GetContext();
VKSDOps *dstOps = context->surface;
const jint sw = sx2 - sx1;
const jint sh = sy2 - sy1;
const jint dw = dx2 - dx1;
const jint dh = dy2 - dy1;
if (sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0) {
J2dTraceLn(J2D_TRACE_ERROR, "MTLBlitLoops_Blit: invalid dimensions");
return;
}
if (!xform) {
clipDestCoords(context,
&dx1, &dy1, &dx2, &dy2,
&sx1, &sy1, &sx2, &sy2,
dstOps->image->extent.width,dstOps->image->extent.height
);
}
SurfaceDataRasInfo srcInfo;
srcInfo.bounds.x1 = sx1;
srcInfo.bounds.y1 = sy1;
srcInfo.bounds.x2 = sx2;
srcInfo.bounds.y2 = sy2;
SurfaceDataRasInfo srcInfo = { .bounds = { sx1, sy1, sx2, sy2 } };
// NOTE: This function will modify the contents of the bounds field to represent the maximum available raster data.
if (srcOps->Lock(env, srcOps, &srcInfo, SD_LOCK_READ) != SD_SUCCESS) {
J2dRlsTraceLn(J2D_TRACE_WARNING, "VKBlitLoops_Blit: could not acquire lock");
if (src->Lock(env, src, &srcInfo, SD_LOCK_READ) != SD_SUCCESS) {
J2dRlsTraceLn(J2D_TRACE_WARNING, "VKRenderer_Blit: could not acquire lock");
return;
}
if (srcInfo.bounds.x2 > srcInfo.bounds.x1 && srcInfo.bounds.y2 > srcInfo.bounds.y1) {
jdouble dstX1 = dx1;
jdouble dstY1 = dy1;
jdouble dstX2 = dx2;
jdouble dstY2 = dy2;
srcOps->GetRasInfo(env, srcOps, &srcInfo);
src->GetRasInfo(env, src, &srcInfo);
if (srcInfo.rasBase) {
if (srcInfo.bounds.x1 != sx1) {
const int dx = srcInfo.bounds.x1 - sx1;
dstX1 += dx * (dw / sw);
}
if (srcInfo.bounds.y1 != sy1) {
const int dy = srcInfo.bounds.y1 - sy1;
dstY1 += dy * (dh / sh);
}
if (srcInfo.bounds.x2 != sx2) {
const int dx = srcInfo.bounds.x2 - sx2;
dstX2 += dx * (dw / sw);
}
if (srcInfo.bounds.y2 != sy2) {
const int dy = srcInfo.bounds.y2 - sy2;
dstY2 += dy * (dh / sh);
if (srcInfo.bounds.x1 != sx1) dx1 += (srcInfo.bounds.x1 - sx1) * (dx2 - dx1) / (sx2 - sx1);
if (srcInfo.bounds.y1 != sy1) dy1 += (srcInfo.bounds.y1 - sy1) * (dy2 - dy1) / (sy2 - sy1);
if (srcInfo.bounds.x2 != sx2) dx2 += (srcInfo.bounds.x2 - sx2) * (dx2 - dx1) / (sx2 - sx1);
if (srcInfo.bounds.y2 != sy2) dy2 += (srcInfo.bounds.y2 - sy2) * (dy2 - dy1) / (sy2 - sy1);
jint sw = (sx2 = srcInfo.bounds.x2) - (sx1 = srcInfo.bounds.x1);
jint sh = (sy2 = srcInfo.bounds.y2) - (sy1 = srcInfo.bounds.y1);
// Need to validate render pass early, as image may not yet be configured.
AlphaType alphaType = getSrcAlphaType(srctype);
if (!VKRenderer_Validate(SHADER_BLIT, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, alphaType)) return;
VKDevice* device = context->surface->device;
BlitSrcType type = decodeSrcType(device, srctype);
VKTexturePoolHandle* imageHandle = VKTexturePool_GetTexture(device->texturePool, sw, sh, type.format);
VKImage* image = VKTexturePoolHandle_GetTexture(imageHandle);
VkDeviceSize dataSize = sh * sw * srcInfo.pixelStride;
VKBuffer buffer;
VKMemory page = VKBuffer_CreateBuffers(device, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VKBlitLoops_FindStageBufferMemoryType,
dataSize, 0, &(uint32_t){1}, &buffer);
char* raster = (char*) srcInfo.rasBase + sy1 * srcInfo.scanStride + sx1 * srcInfo.pixelStride;
for (size_t row = 0; row < (size_t) sh; row++) {
memcpy((char*) buffer.data + row * sw * srcInfo.pixelStride, raster, sw * srcInfo.pixelStride);
raster += (uint32_t) srcInfo.scanStride;
}
VKBlitSwToTextureViaPooledTexture(context, dstOps, &srcInfo, srctype, hint,
(int)dstX1, (int)dstY1,
(int)dstX2, (int)dstY2);
{
VkBufferMemoryBarrier bufferBarrier;
VKBarrierBatch bufferBatch = {};
VKBuffer_AddBarrier(&bufferBarrier, &bufferBatch, &buffer,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT);
VkImageMemoryBarrier imageBarrier;
VKBarrierBatch imageBatch = {};
VKImage_AddBarrier(&imageBarrier, &imageBatch, image,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
VKRenderer_RecordBarriers(device->renderer, &bufferBarrier, &bufferBatch, &imageBarrier, &imageBatch);
}
VkBufferImageCopy region = (VkBufferImageCopy) {
.bufferOffset = 0,
.bufferRowLength = 0,
.bufferImageHeight = 0,
.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.imageSubresource.mipLevel = 0,
.imageSubresource.baseArrayLayer = 0,
.imageSubresource.layerCount = 1,
.imageOffset = {0, 0, 0},
.imageExtent = {
.width = sw,
.height = sh,
.depth = 1
}
};
device->vkCmdCopyBufferToImage(VKRenderer_Record(device->renderer), buffer.handle, image->handle,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
{
VkImageMemoryBarrier barrier;
VKBarrierBatch barrierBatch = {};
VKImage_AddBarrier(&barrier, &barrierBatch, image,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
VKRenderer_RecordBarriers(device->renderer, NULL, NULL, &barrier, &barrierBatch);
}
VKRenderer_DrawImage(image, type.format, type.swizzle, hint, SAMPLER_WRAP_BORDER,
0, 0, (float)sw, (float)sh, (float)dx1, (float)dy1, (float)dx2, (float)dy2);
VKRenderer_FlushMemoryOnReset(context->surface->renderPass, buffer.range);
VKRenderer_ExecOnCleanup(context->surface->renderPass, VKBlitLoops_DisposeTexture, imageHandle);
VKRenderer_ExecOnCleanup(context->surface->renderPass, VKBlitLoops_DisposeBuffer, buffer.handle);
VKRenderer_ExecOnCleanup(context->surface->renderPass, VKBlitLoops_DisposeMemory, page);
} else {
J2dRlsTraceLn(J2D_TRACE_ERROR, "VKRenderer_Blit: could not get raster info");
}
SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
SurfaceData_InvokeRelease(env, src, &srcInfo);
}
SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
}
static void VKBlitLoops_FindStageBufferMemoryType(VKMemoryRequirements* requirements) {
VKAllocator_FindMemoryType(requirements, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT,
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
VKAllocator_FindMemoryType(requirements, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_ALL_MEMORY_PROPERTIES);
SurfaceData_InvokeUnlock(env, src, &srcInfo);
}
/**

View File

@@ -41,13 +41,12 @@ void VKBlitLoops_IsoBlit(VKSDOps* srcOps,
jdouble dx2, jdouble dy2);
void VKBlitLoops_Blit(JNIEnv *env,
jlong pSrcOps,
jboolean xform, jint hint,
jshort srctype,
jint sx1, jint sy1,
jint sx2, jint sy2,
jdouble dx1, jdouble dy1,
jdouble dx2, jdouble dy2);
SurfaceDataOps* src,
jshort srctype, jint hint,
jint sx1, jint sy1,
jint sx2, jint sy2,
jdouble dx1, jdouble dy1,
jdouble dx2, jdouble dy2);
void
VKBlitLoops_SurfaceToSwBlit(JNIEnv *env,

View File

@@ -352,10 +352,9 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
dx1, dy1, dx2, dy2);
} else {
jshort srctype = EXTRACT_SHORT(packedParams, OFFSET_SRCTYPE);
VKBlitLoops_Blit(env, ptr_to_jlong(src),
xform, hint, srctype,
sx1, sy1, sx2, sy2,
dx1, dy1, dx2, dy2);
VKBlitLoops_Blit(env, src, srctype, hint,
sx1, sy1, sx2, sy2,
dx1, dy1, dx2, dy2);
}
context->surface = oldSurface;
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: BLIT %p -> %p ", src, dst)

View File

@@ -645,7 +645,7 @@ static void VKRenderer_ResetDrawing(VKSDOps* surface) {
}
size_t vertexBufferCount = ARRAY_SIZE(surface->renderPass->vertexBuffers);
size_t maskFillBufferCount = ARRAY_SIZE(surface->renderPass->maskFillBuffers);
size_t cleanupQueueCount = ARRAY_SIZE(surface->renderPass->cleanupQueue);;
size_t cleanupQueueCount = ARRAY_SIZE(surface->renderPass->cleanupQueue);
VkMappedMemoryRange memoryRanges[vertexBufferCount + maskFillBufferCount];
for (uint32_t i = 0; i < vertexBufferCount; i++) {
POOL_RETURN(surface->device->renderer, vertexBufferPool, surface->renderPass->vertexBuffers[i]);
@@ -1263,10 +1263,12 @@ static void VKRenderer_SetupStencil(const VKRenderingContext* context) {
renderPass->state.shader = NO_SHADER;
}
void VKRenderer_DisposeOnCleanup(VKRenderer* renderer, VKCleanupHandler hnd, void* data) {
if (renderer == NULL) return;
VKCleanupEntry entry = {hnd, data};
POOL_RETURN(renderer, cleanupQueue, entry);
void VKRenderer_ExecOnCleanup(VKRenderPass* renderPass, VKCleanupHandler hnd, void* data) {
ARRAY_PUSH_BACK(renderPass->cleanupQueue) = (VKCleanupEntry) { hnd, data };
}
void VKRenderer_FlushMemoryOnReset(VKRenderPass* renderPass, VkMappedMemoryRange range) {
ARRAY_PUSH_BACK(renderPass->flushRanges) = range;
}
void VKRenderer_RecordBarriers(VKRenderer* renderer,
@@ -1495,11 +1497,10 @@ void VKRenderer_MaskFill(jint x, jint y, jint w, jint h,
vs[3] = p1; vs[4] = p3; vs[5] = p4;
}
void VKRenderer_DrawImage(VKImage* image, AlphaType alphaType, VkFormat format,
void VKRenderer_DrawImage(VKImage* image, VkFormat format,
VKPackedSwizzle swizzle, jint filter, VKSamplerWrap wrap,
float sx1, float sy1, float sx2, float sy2,
float dx1, float dy1, float dx2, float dy2) {
if (!VKRenderer_Validate(SHADER_BLIT, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, alphaType)) return;
VKSDOps* surface = VKRenderer_GetContext()->surface;
VKDevice* device = surface->device;

View File

@@ -117,7 +117,12 @@ VkBool32 VKRenderer_FlushRenderPass(VKSDOps* surface);
/**
* Register a handler to be called at the cleanup phase of the renderer.
*/
void VKRenderer_DisposeOnCleanup(VKRenderer* renderer, VKCleanupHandler hnd, void* data);
void VKRenderer_ExecOnCleanup(VKRenderPass* renderPass, VKCleanupHandler hnd, void* data);
/**
* Register a memory range that will be flushed on render pass reset drawing.
*/
void VKRenderer_FlushMemoryOnReset(VKRenderPass* renderPass, VkMappedMemoryRange range);
/**
* Flush pending render pass and queue surface for presentation (if applicable).
@@ -151,7 +156,7 @@ void VKRenderer_FillSpans(jint spanCount, jint *spans);
void VKRenderer_MaskFill(jint x, jint y, jint w, jint h,
jint maskoff, jint maskscan, jint masklen, uint8_t *mask);
void VKRenderer_DrawImage(VKImage* image, AlphaType alphaType, VkFormat format,
void VKRenderer_DrawImage(VKImage* image, VkFormat format,
VKPackedSwizzle swizzle, jint filter, VKSamplerWrap wrap,
float sx1, float sy1, float sx2, float sy2,
float dx1, float dy1, float dx2, float dy2);