Skip to content

Commit

Permalink
JBR-7990 Vulkan: Robot pixel grabbing for Vulkan surfaces
Browse files Browse the repository at this point in the history
Implemented grabbing pixel via partly supported SurfaceToSwBlit
  • Loading branch information
avu authored and jbrbot committed Jan 14, 2025
1 parent b2715de commit 5721326
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 4 deletions.
112 changes: 112 additions & 0 deletions src/java.desktop/share/native/common/java2d/vulkan/VKBlitLoops.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "VKBlitLoops.h"
#include "VKSurfaceData.h"
#include "VKRenderer.h"
#include "GraphicsPrimitiveMgr.h"


#include "Trace.h"
Expand Down Expand Up @@ -316,4 +317,115 @@ void VKBlitLoops_Blit(JNIEnv *env,
SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
}
SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
}

/**
* Specialized blit method for copying a native OpenGL "Surface" (pbuffer,
* window, etc.) to a system memory ("Sw") surface.
*/
void
VKBlitLoops_SurfaceToSwBlit(JNIEnv *env, VKRenderingContext* context,
jlong pSrcOps, jlong pDstOps, jint dsttype,
jint srcx, jint srcy, jint dstx, jint dsty,
jint width, jint height)
{
VKSDOps *srcOps = (VKSDOps *)jlong_to_ptr(pSrcOps);
SurfaceDataOps *dstOps = (SurfaceDataOps *)jlong_to_ptr(pDstOps);
SurfaceDataRasInfo srcInfo, dstInfo;

J2dTraceLn(J2D_TRACE_INFO, "VKBlitLoops_SurfaceToSwBlit");

if (width <= 0 || height <= 0) {
J2dTraceLn(J2D_TRACE_WARNING,
"VKBlitLoops_SurfaceToSwBlit: dimensions are non-positive");
return;
}

RETURN_IF_NULL(srcOps);
RETURN_IF_NULL(dstOps);
RETURN_IF_NULL(context);

VKDevice* device = srcOps->device;
VKImage* image = srcOps->image;

if (image == NULL || device == NULL) {
J2dRlsTraceLn2(J2D_TRACE_ERROR,
"VKBlitLoops_SurfaceToSwBlit: image(%p) or device(%p) is NULL", image, device)
return;
}

srcInfo.bounds.x1 = srcx;
srcInfo.bounds.y1 = srcy;
srcInfo.bounds.x2 = srcx + width;
srcInfo.bounds.y2 = srcy + height;
dstInfo.bounds.x1 = dstx;
dstInfo.bounds.y1 = dsty;
dstInfo.bounds.x2 = dstx + width;
dstInfo.bounds.y2 = dsty + height;

if (dstOps->Lock(env, dstOps, &dstInfo, SD_LOCK_WRITE) != SD_SUCCESS) {
J2dTraceLn(J2D_TRACE_WARNING,
"VKBlitLoops_SurfaceToSwBlit: could not acquire dst lock");
return;
}

SurfaceData_IntersectBoundsXYXY(&srcInfo.bounds,
0, 0, srcOps->image->extent.width, srcOps->image->extent.height);
SurfaceData_IntersectBlitBounds(&dstInfo.bounds, &srcInfo.bounds,
srcx - dstx, srcy - dsty);

if (srcInfo.bounds.x2 > srcInfo.bounds.x1 &&
srcInfo.bounds.y2 > srcInfo.bounds.y1)
{
dstOps->GetRasInfo(env, dstOps, &dstInfo);
if (dstInfo.rasBase) {
void *pDst = dstInfo.rasBase;
srcx = srcInfo.bounds.x1;
srcy = srcInfo.bounds.y1;
dstx = dstInfo.bounds.x1;
dsty = dstInfo.bounds.y1;
width = srcInfo.bounds.x2 - srcInfo.bounds.x1;
height = srcInfo.bounds.y2 - srcInfo.bounds.y1;
jsize bufferSizeInPixels = width * height;

pDst = PtrAddBytes(pDst, dstx * dstInfo.pixelStride);
pDst = PtrPixelsRow(pDst, dsty, dstInfo.scanStride);

VKRenderer_FlushRenderPass(srcOps);
VkCommandBuffer cb = VKRenderer_Record(device->renderer);

VKBuffer* buffer = VKBuffer_Create(device, bufferSizeInPixels * sizeof(jint),
VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);

VkBufferImageCopy region = {
.bufferOffset = 0,
.bufferRowLength = 0,
.bufferImageHeight = 0,
.imageSubresource= {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1
},
.imageOffset = {srcInfo.bounds.x1, srcInfo.bounds.y1, 0},
.imageExtent = {srcInfo.bounds.x2 - srcInfo.bounds.x1,
srcInfo.bounds.y2 - srcInfo.bounds.y1, 1}
};

device->vkCmdCopyImageToBuffer(cb, image->handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
buffer->handle,
1, &region);
VKRenderer_Flush(device->renderer);
VKRenderer_Sync(device->renderer);
void* pixelData;
device->vkMapMemory(device->handle, buffer->range.memory, 0, VK_WHOLE_SIZE, 0, &pixelData);
memcpy(pDst, pixelData, bufferSizeInPixels * sizeof(jint));
device->vkUnmapMemory(device->handle, buffer->range.memory);
VKBuffer_Destroy(device, buffer);
}
SurfaceData_InvokeRelease(env, dstOps, &dstInfo);
}
SurfaceData_InvokeUnlock(env, dstOps, &dstInfo);
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,10 @@ void VKBlitLoops_Blit(JNIEnv *env,
jdouble dx1, jdouble dy1,
jdouble dx2, jdouble dy2);

void
VKBlitLoops_SurfaceToSwBlit(JNIEnv *env, VKRenderingContext* context,
jlong pSrcOps, jlong pDstOps, jint dsttype,
jint srcx, jint srcy, jint dstx, jint dsty,
jint width, jint height);

#endif /* VKBlitLoops_h_Included */
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
jlong pSrc = NEXT_LONG(b);
jlong pDst = NEXT_LONG(b);
J2dRlsTraceLn(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: SURFACE_TO_SW_BLIT");
VKBlitLoops_SurfaceToSwBlit(env, &context, pSrc, pDst, dsttype, sx, sy, dx, dy, w, h);
}
break;
case sun_java2d_pipe_BufferedOpCodes_MASK_FILL:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,18 @@

package sun.java2d.vulkan;

import java.awt.AlphaComposite;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import sun.awt.image.BufImgSurfaceData;
import sun.awt.wl.WLComponentPeer;
import sun.java2d.SurfaceData;
import sun.java2d.loops.Blit;
import sun.java2d.loops.CompositeType;
import sun.java2d.loops.SurfaceType;
import sun.java2d.pipe.BufferedContext;
import sun.java2d.pipe.RenderBuffer;
Expand Down Expand Up @@ -147,8 +152,20 @@ public static WLVKGraphicsConfig getGC(WLComponentPeer peer) {
}

public int getRGBPixelAt(int x, int y) {
int pixel = pixelAt(x, y);
return getSurfaceType().rgbFor(pixel, getColorModel());
Rectangle r = peer.getBufferBounds();
if (x < r.x || x >= r.x + r.width || y < r.y || y >= r.y + r.height) {
throw new ArrayIndexOutOfBoundsException("x,y outside of buffer bounds");
}

BufferedImage resImg = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
SurfaceData resData = BufImgSurfaceData.createData(resImg);

Blit blit = Blit.getFromCache(getSurfaceType(), CompositeType.SrcNoEa,
resData.getSurfaceType());
blit.Blit(this, resData, AlphaComposite.Src, null,
x, y, 0, 0, 1, 1);

return resImg.getRGB(0, 0);
}

public int [] getRGBPixelsAt(Rectangle bounds) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,6 @@ Java_sun_java2d_vulkan_WLVKSurfaceData_pixelsAt(JNIEnv *env, jobject vksd, jint
J2dTraceLn(J2D_TRACE_INFO, "Java_sun_java2d_vulkan_WLVKSurfaceData_pixelsAt")
VKWinSDOps* sd = (VKWinSDOps*)SurfaceData_GetOps(env, vksd);

JNU_CHECK_EXCEPTION_RETURN(env, NULL);

if (sd == NULL) {
return NULL;
}
Expand Down Expand Up @@ -181,6 +179,8 @@ Java_sun_java2d_vulkan_WLVKSurfaceData_pixelsAt(JNIEnv *env, jobject vksd, jint
jsize bufferSizeInPixels = width * height;
arrayObj = (*env)->NewIntArray(env, bufferSizeInPixels);

JNU_CHECK_EXCEPTION_RETURN(env, NULL);

VKRenderer_FlushRenderPass(&sd->vksdOps);
VkCommandBuffer cb = VKRenderer_Record(device->renderer);

Expand Down

0 comments on commit 5721326

Please sign in to comment.