From 95ada30c3fddaa507ad337cc0bff23a43cb15fc6 Mon Sep 17 00:00:00 2001 From: Artem Bochkarev Date: Wed, 4 Oct 2023 10:05:41 +0400 Subject: [PATCH] JBR-5405: implementation of direct raster loading for VolatileImage --- .../sun/java2d/metal/MTLSurfaceData.java | 26 +++ .../libawt_lwawt/java2d/metal/MTLBlitLoops.m | 17 ++ .../java2d/metal/MTLSurfaceData.m | 39 +++++ .../com/jetbrains/desktop/JBRApiModule.java | 3 + .../jetbrains/desktop/NativeRasterLoader.java | 28 ++++ .../sun/java2d/NativeRasterLoader.java | 21 +++ .../share/classes/sun/java2d/SurfaceData.java | 15 ++ .../sun/java2d/opengl/OGLSurfaceData.java | 26 +++ .../common/java2d/opengl/OGLBlitLoops.c | 38 +++++ .../common/java2d/opengl/OGLSurfaceData.c | 72 +++++++++ .../classes/sun/java2d/x11/XSurfaceData.java | 13 ++ .../classes/sun/java2d/xr/XRSurfaceData.java | 16 ++ .../native/common/java2d/x11/X11SurfaceData.c | 87 ++++++++++ .../sun/java2d/d3d/D3DSurfaceData.java | 28 ++++ .../libawt/java2d/d3d/D3DSurfaceData.cpp | 153 ++++++++++++++++++ .../src/com/jetbrains/NativeRasterLoader.java | 18 +++ src/jetbrains.api/version.properties | 4 +- 17 files changed, 602 insertions(+), 2 deletions(-) create mode 100644 src/java.desktop/share/classes/com/jetbrains/desktop/NativeRasterLoader.java create mode 100644 src/java.desktop/share/classes/sun/java2d/NativeRasterLoader.java create mode 100644 src/jetbrains.api/src/com/jetbrains/NativeRasterLoader.java diff --git a/src/java.desktop/macosx/classes/sun/java2d/metal/MTLSurfaceData.java b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLSurfaceData.java index 265e3d5631ab..3606ea11f1ac 100644 --- a/src/java.desktop/macosx/classes/sun/java2d/metal/MTLSurfaceData.java +++ b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLSurfaceData.java @@ -640,4 +640,30 @@ public abstract class MTLSurfaceData extends SurfaceData rq.unlock(); } } + + /** + * Loads native image raster into surface. + * + * @param pRaster native pointer image raster with 8-bit RGBA color components packed into integer pixels. + * Note: The color data in this image is considered to be premultiplied with alpha. + * @param width width of image in pixels + * @param height height of image in pixels + * @param pRects native pointer to array of "dirty" rects, each rect is a sequence of four 32-bit integers: x, y, width, heigth + * Note: can be null (then whole image used) + * @param rectsCount count of "dirty" rects (if 0 then whole image used) + */ + @Override + protected void loadNativeRaster(long pRaster, int width, int height, long pRects, int rectsCount) { + MTLRenderQueue rq = MTLRenderQueue.getInstance(); + rq.lock(); + try { + MTLContext.setScratchSurface(getMTLGraphicsConfig()); + rq.flushAndInvokeNow(() -> loadNativeRasterWithRects(getNativeOps(), pRaster, width, height, pRects, rectsCount)); + } finally { + rq.unlock(); + } + markDirty(); + } + + private static native boolean loadNativeRasterWithRects(long sdops, long pRaster, int width, int height, long pRects, int rectsCount); } diff --git a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLBlitLoops.m b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLBlitLoops.m index f1cc4fd435b9..424edee643dd 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLBlitLoops.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLBlitLoops.m @@ -240,6 +240,23 @@ replaceTextureRegion(MTLContext *mtlc, id dest, const SurfaceDataRas } } +void replaceTexture(MTLContext *mtlc, id dest, void* pRaster, int width, int height, int dx1, int dy1, int dx2, int dy2) { + MTLRasterFormatInfo rfi = RasterFormatInfos[0]; + + SurfaceDataRasInfo srcInfo; + memset(&srcInfo, 0, sizeof(SurfaceDataRasInfo)); + srcInfo.bounds.x1 = dx1; + srcInfo.bounds.y1 = dy1; + srcInfo.bounds.x2 = dx2; + srcInfo.bounds.y2 = dy2; + srcInfo.scanStride = width*4; + srcInfo.pixelStride = 4; + srcInfo.rasBase = pRaster; + srcInfo.pixelBitOffset = 0; + + replaceTextureRegion(mtlc, dest, &srcInfo, &rfi, dx1, dy1, dx2, dy2); +} + /** * Inner loop used for copying a source system memory ("Sw") surface to a * destination MTL "Surface". This method is invoked from diff --git a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLSurfaceData.m b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLSurfaceData.m index 1c793799221c..3083fcffb47a 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLSurfaceData.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLSurfaceData.m @@ -348,6 +348,8 @@ Java_sun_java2d_metal_MTLSurfaceData_initOps } } +extern void replaceTexture(MTLContext *mtlc, id dest, void* pRaster, int width, int height, int dx1, int dy1, int dx2, int dy2); + JNIEXPORT void JNICALL Java_sun_java2d_metal_MTLSurfaceData_clearWindow (JNIEnv *env, jobject mtlsd) @@ -362,6 +364,43 @@ Java_sun_java2d_metal_MTLSurfaceData_clearWindow mtlsdo->layer = NULL; } +JNIEXPORT jboolean JNICALL +Java_sun_java2d_metal_MTLSurfaceData_loadNativeRasterWithRects + (JNIEnv *env, jclass clazz, + jlong sdops, jlong pRaster, jint width, jint height, jlong pRects, jint rectsCount) +{ + BMTLSDOps *dstOps = (BMTLSDOps *)jlong_to_ptr(sdops); + if (dstOps == NULL || pRaster == 0) { + J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_loadNativeRasterWithRects: params are null"); + return JNI_FALSE; + } + + id dest = dstOps->pTexture; + if (dest == NULL) { + J2dTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_loadNativeRasterWithRects: dest is null"); + return JNI_FALSE; + } + + MTLSDOps *dstMTLOps = (MTLSDOps *)dstOps->privOps; + MTLContext *ctx = dstMTLOps->configInfo->context; + if (pRects == 0 || rectsCount < 1) { + J2dTraceLn(J2D_TRACE_VERBOSE, "MTLSurfaceData_loadNativeRasterWithRects: do full copy of raster:"); + replaceTexture(ctx, dest, (void*)pRaster, (int)width, (int)height, 0, 0, (int)width, (int)height); + } else { + int32_t *pr = (int32_t *) pRects; + for (int c = 0; c < rectsCount; ++c) { + int32_t x = *(pr++); + int32_t y = *(pr++); + int32_t w = *(pr++); + int32_t h = *(pr++); + //fprintf(stderr, "MTLSurfaceData_loadNativeRasterWithRects: process rect %d %d %d %d\n", x, y, w, h); + replaceTexture(ctx, dest, (void*)pRaster, (int)width, (int)height, x, y, x + w, y + h); + } + } + + return JNI_TRUE; +} + NSString * getSurfaceDescription(const BMTLSDOps * bmtlsdOps) { if (bmtlsdOps == NULL) return @"NULL"; diff --git a/src/java.desktop/share/classes/com/jetbrains/desktop/JBRApiModule.java b/src/java.desktop/share/classes/com/jetbrains/desktop/JBRApiModule.java index e09275c1c9a3..1da366fbe574 100644 --- a/src/java.desktop/share/classes/com/jetbrains/desktop/JBRApiModule.java +++ b/src/java.desktop/share/classes/com/jetbrains/desktop/JBRApiModule.java @@ -63,6 +63,9 @@ public class JBRApiModule { .withStatic("getFeaturesAsString", "getFeaturesAsString", "com.jetbrains.desktop.FontExtensions") .clientProxy("java.awt.Font$Features", "com.jetbrains.FontExtensions$Features") .service("com.jetbrains.WindowMove", "java.awt.Window$WindowMoveService") + .service("com.jetbrains.NativeRasterLoader") + .withStatic("loadNativeRaster", "loadNativeRaster", "com.jetbrains.desktop.NativeRasterLoader") + ; } } diff --git a/src/java.desktop/share/classes/com/jetbrains/desktop/NativeRasterLoader.java b/src/java.desktop/share/classes/com/jetbrains/desktop/NativeRasterLoader.java new file mode 100644 index 000000000000..7b9a6f30443f --- /dev/null +++ b/src/java.desktop/share/classes/com/jetbrains/desktop/NativeRasterLoader.java @@ -0,0 +1,28 @@ +package com.jetbrains.desktop; + +import sun.awt.image.SunVolatileImage; + +import java.awt.image.VolatileImage; + +class NativeRasterLoader { + /** + * Loads native image raster into VolatileImage + * + * @param pRaster native pointer image raster with 8-bit RGBA color components packed into integer pixels. + * Note: The color data in this image is considered to be premultiplied with alpha. + * @param width width of image in pixels + * @param height height of image in pixels + * @param pRects native pointer to array of "dirty" rects, each rect is a sequence of four 32-bit integers: x, y, width, heigth + * Note: can be null (then whole image used) + * @param rectsCount count of "dirty" rects (if 0 then whole image used) + */ + static void loadNativeRaster(VolatileImage vi, long pRaster, int width, int height, long pRects, int rectsCount) { + if (!(vi instanceof SunVolatileImage)) { + System.err.printf("Unsupported type of VolatileImage: %s\n", vi); + return; + } + + SunVolatileImage svi = (SunVolatileImage)vi; + sun.java2d.NativeRasterLoader.loadNativeRaster(svi.getDestSurface(), pRaster, width, height, pRects, rectsCount); + } +} \ No newline at end of file diff --git a/src/java.desktop/share/classes/sun/java2d/NativeRasterLoader.java b/src/java.desktop/share/classes/sun/java2d/NativeRasterLoader.java new file mode 100644 index 000000000000..479802a80c27 --- /dev/null +++ b/src/java.desktop/share/classes/sun/java2d/NativeRasterLoader.java @@ -0,0 +1,21 @@ +package sun.java2d; + +public class NativeRasterLoader { + /** + * Loads native image raster into surface. + * + * @param pRaster native pointer image raster with 8-bit RGBA color components packed into integer pixels. + * Note: The color data in this image is considered to be premultiplied with alpha. + * @param width width of image in pixels + * @param height height of image in pixels + * @param pRects native pointer to array of "dirty" rects, each rect is a sequence of four 32-bit integers: x, y, width, heigth + * Note: can be null (then whole image used) + * @param rectsCount count of "dirty" rects (if 0 then whole image used) + */ + public static void loadNativeRaster(Surface surface, long pRaster, int width, int height, long pRects, int rectsCount) { + if (surface instanceof SurfaceData) { + SurfaceData sd = (SurfaceData)surface; + sd.loadNativeRaster(pRaster, width, height, pRects, rectsCount); + } + } +} \ No newline at end of file diff --git a/src/java.desktop/share/classes/sun/java2d/SurfaceData.java b/src/java.desktop/share/classes/sun/java2d/SurfaceData.java index e91055044818..ad09030ec824 100644 --- a/src/java.desktop/share/classes/sun/java2d/SurfaceData.java +++ b/src/java.desktop/share/classes/sun/java2d/SurfaceData.java @@ -1091,4 +1091,19 @@ public abstract class SurfaceData public double getDefaultScaleY() { return 1; } + + /** + * Loads native image raster into surface. + * + * @param pRaster native pointer image raster with 8-bit RGBA color components packed into integer pixels. + * Note: The color data in this image is considered to be premultiplied with alpha. + * @param width width of image in pixels + * @param height height of image in pixels + * @param pRects native pointer to array of "dirty" rects, each rect is a sequence of four 32-bit integers: x, y, width, heigth + * Note: can be null (then whole image used) + * @param rectsCount count of "dirty" rects (if 0 then whole image used) + */ + protected void loadNativeRaster(long pRaster, int width, int height, long pRects, int rectsCount) { + System.err.println("ERROR: loadNativeRaster must be overriden."); + } } diff --git a/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceData.java b/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceData.java index 553675cbc016..838a3338f2c6 100644 --- a/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceData.java +++ b/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceData.java @@ -654,4 +654,30 @@ public abstract class OGLSurfaceData extends SurfaceData boolean isOnScreen() { return getType() == WINDOW; } + + /** + * Loads native image raster into surface. + * + * @param pRaster native pointer image raster with 8-bit RGBA color components packed into integer pixels. + * Note: The color data in this image is considered to be premultiplied with alpha. + * @param width width of image in pixels + * @param height height of image in pixels + * @param pRects native pointer to array of "dirty" rects, each rect is a sequence of four 32-bit integers: x, y, width, heigth + * Note: can be null (then whole image used) + * @param rectsCount count of "dirty" rects (if 0 then whole image used) + */ + @Override + protected void loadNativeRaster(long pRaster, int width, int height, long pRects, int rectsCount) { + OGLRenderQueue rq = OGLRenderQueue.getInstance(); + rq.lock(); + try { + OGLContext.setScratchSurface(getOGLGraphicsConfig()); + rq.flushAndInvokeNow(() -> loadNativeRasterWithRects(getNativeOps(), pRaster, width, height, pRects, rectsCount)); + } finally { + rq.unlock(); + } + markDirty(); + } + + private static native boolean loadNativeRasterWithRects(long sdops, long pRaster, int width, int height, long pRects, int rectsCount); } diff --git a/src/java.desktop/share/native/common/java2d/opengl/OGLBlitLoops.c b/src/java.desktop/share/native/common/java2d/opengl/OGLBlitLoops.c index 8e577e117880..f7fcce16dcb1 100644 --- a/src/java.desktop/share/native/common/java2d/opengl/OGLBlitLoops.c +++ b/src/java.desktop/share/native/common/java2d/opengl/OGLBlitLoops.c @@ -238,6 +238,44 @@ OGLBlitSwToSurface(OGLContext *oglc, SurfaceDataRasInfo *srcInfo, } } +void OGLBlitRasterToSurface(OGLSDOps *dstOps, jlong pRaster, jint width, jint height, + OGLPixelFormat *pf, + jint sx1, jint sy1, jint sx2, jint sy2, + jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2) { + SurfaceDataRasInfo srcInfo; + memset(&srcInfo, 0, sizeof(SurfaceDataRasInfo)); + srcInfo.bounds.x1 = 0; + srcInfo.bounds.y1 = 0; + srcInfo.bounds.x2 = width; + srcInfo.bounds.y2 = height; + srcInfo.scanStride = width*4; + srcInfo.pixelStride = 4; + srcInfo.rasBase = (void*)pRaster; + srcInfo.pixelBitOffset = 0; + + unsigned char * r = (unsigned char *)pRaster; + //fprintf(stderr, "OGLBlitRasterToSurface:%d,%d,%d,%d,%d,%d,%d,%d....\n", r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7]); + + if (dstOps->drawableType == OGLSD_FBOBJECT) { + // Note that we unbind the currently bound texture first; this is + // recommended procedure when binding an fbobject + j2d_glBindTexture(dstOps->textureTarget, 0); + j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dstOps->fbobjectID); + } else { + J2dRlsTraceLn1(J2D_TRACE_ERROR, "Unsupported drawable type %d.", dstOps->drawableType); + } + + j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); + j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, srcInfo.scanStride / srcInfo.pixelStride); + j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, pf->alignment); + + OGLBlitSwToSurface(OGLRenderQueue_GetCurrentContext(), &srcInfo, pf, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2); + + j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 4); +} + /** * Inner loop used for copying a source system memory ("Sw") surface or * OpenGL "Surface" to a destination OpenGL "Surface", using an OpenGL texture diff --git a/src/java.desktop/share/native/common/java2d/opengl/OGLSurfaceData.c b/src/java.desktop/share/native/common/java2d/opengl/OGLSurfaceData.c index 59773ec666d3..85f539dcd9fa 100644 --- a/src/java.desktop/share/native/common/java2d/opengl/OGLSurfaceData.c +++ b/src/java.desktop/share/native/common/java2d/opengl/OGLSurfaceData.c @@ -41,6 +41,10 @@ extern jboolean OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo); extern void OGLSD_DestroyOGLSurface(JNIEnv *env, OGLSDOps *oglsdo); void OGLSD_SetNativeDimensions(JNIEnv *env, OGLSDOps *oglsdo, jint w, jint h); +extern void OGLBlitRasterToSurface(OGLSDOps *dstOps, jlong pRaster, jint width, jint height, + OGLPixelFormat *pf, + jint sx1, jint sy1, jint sx2, jint sy2, + jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2); /** * This table contains the "pixel formats" for all system memory surfaces @@ -526,6 +530,74 @@ Java_sun_java2d_opengl_OGLSurfaceData_getTextureID return (jint)oglsdo->textureID; } +JNIEXPORT jboolean JNICALL +Java_sun_java2d_opengl_OGLSurfaceData_loadNativeRasterWithRects + (JNIEnv *env, jclass clazz, + jlong sdops, jlong pRaster, jint width, jint height, jlong pRects, jint rectsCount) +{ + OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(sdops); + if (oglsdo == NULL || pRaster == 0) { + J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSurfaceData_loadNativeRasterWithRects: params are null"); + return JNI_FALSE; + } + //fprintf(stderr, "OGLSurfaceData_loadNativeRasterWithRects: ops=%p r=%p rCount=%d tt=%d texId=%d\n", (void*)sdops, (void*)pRaster, rectsCount, oglsdo->textureTarget, oglsdo->textureID); + + // Set state. + OGLPixelFormat pf = PixelFormats[1]; + const int viaTexSubImage = oglsdo->drawableType != OGLSD_FBOBJECT; + // NOTE: both types works correctly under OSX (probably need to choose the fastest one) + if (viaTexSubImage) { + J2dTraceLn(J2D_TRACE_VERBOSE, "OGLSurfaceData_loadNativeRasterWithRects: via glTexSubImage2D"); + j2d_glEnable(GL_TEXTURE_2D); + j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, width); + j2d_glBindTexture(GL_TEXTURE_2D, oglsdo->textureID); + } else { + J2dTraceLn(J2D_TRACE_VERBOSE, "OGLSurfaceData_loadNativeRasterWithRects: via glDrawPix (i.e. OGLBlitSwToSurface)"); + } + + // Render. + if (pRects == 0 || rectsCount < 1) { + J2dTraceLn(J2D_TRACE_VERBOSE, "OGLSurfaceData_loadNativeRasterWithRects: do full copy of raster:"); + //unsigned char * r = (unsigned char *)pRaster; + //fprintf(stderr, "\t %d,%d,%d,%d,%d,%d,%d,%d....\n", r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7]); + if (viaTexSubImage) { + j2d_glTexSubImage2D(oglsdo->textureTarget, 0, + 0, 0, width, height, + pf.format, pf.type, (GLvoid*)pRaster); + } else { + OGLBlitRasterToSurface(oglsdo, pRaster, width, height, &pf, + 0, 0, width, height, + 0, 0, width, height); } + } else { + int32_t *pr = (int32_t *) pRects; + for (int c = 0; c < rectsCount; ++c) { + int32_t x = *(pr++); + int32_t y = *(pr++); + int32_t w = *(pr++); + int32_t h = *(pr++); + if (viaTexSubImage) { + const GLvoid *srcBytes = (char *)pRaster + y*width*4 + x*4; + //fprintf(stderr, "\t[%d, %d, %d, %d] %d\n", x, y, w, h, (int)((char*)srcBytes - (char*)pRaster)); + j2d_glTexSubImage2D(oglsdo->textureTarget, 0, + x, y, w, h, + pf.format, pf.type, srcBytes); + } else { + OGLBlitRasterToSurface(oglsdo, pRaster, width, height, &pf, + x, y, x + w, y + h, + x, y, x + w, y + h); + } + } + } + + // Restore state. + if (viaTexSubImage) { + j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + } + + return JNI_TRUE; +} + + /** * Initializes nativeWidth/Height fields of the surfaceData object with * passed arguments. diff --git a/src/java.desktop/unix/classes/sun/java2d/x11/XSurfaceData.java b/src/java.desktop/unix/classes/sun/java2d/x11/XSurfaceData.java index dbae176dd7e6..c35e3a8e8a1a 100644 --- a/src/java.desktop/unix/classes/sun/java2d/x11/XSurfaceData.java +++ b/src/java.desktop/unix/classes/sun/java2d/x11/XSurfaceData.java @@ -61,4 +61,17 @@ public abstract class XSurfaceData extends SurfaceData { protected native void setInvalid(); protected static native void XSetGraphicsExposures(long xgc, boolean needExposures); + + /** + * Loads native image raster into surface. + * + * @param pRaster native pointer image raster with 8-bit RGBA color components packed into integer pixels. + * Note: The color data in this image is considered to be premultiplied with alpha. + * @param width width of image in pixels + * @param height height of image in pixels + * @param pRects native pointer to array of "dirty" rects, each rect is a sequence of four 32-bit integers: x, y, width, heigth + * Note: can be null (then whole image used) + * @param rectsCount count of "dirty" rects (if 0 then whole image used) + */ + protected static native boolean loadNativeRasterWithRects(long sdops, long pRaster, int width, int height, long pRects, int rectsCount); } diff --git a/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceData.java b/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceData.java index 6f3e3501c283..2724e900ab19 100644 --- a/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceData.java +++ b/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceData.java @@ -761,4 +761,20 @@ public abstract class XRSurfaceData extends XSurfaceData { public void setStaticSrcTx(AffineTransform staticSrcTx) { this.staticSrcTx = staticSrcTx; } + + /** + * Loads native image raster into surface. + * + * @param pRaster native pointer image raster with 8-bit RGBA color components packed into integer pixels. + * Note: The color data in this image is considered to be premultiplied with alpha. + * @param width width of image in pixels + * @param height height of image in pixels + * @param pRects native pointer to array of "dirty" rects, each rect is a sequence of four 32-bit integers: x, y, width, heigth + * Note: can be null (then whole image used) + * @param rectsCount count of "dirty" rects (if 0 then whole image used) + */ + @Override + protected void loadNativeRaster(long pRaster, int width, int height, long pRects, int rectsCount) { + loadNativeRasterWithRects(getNativeOps(), pRaster, width, height, pRects, rectsCount); + } } diff --git a/src/java.desktop/unix/native/common/java2d/x11/X11SurfaceData.c b/src/java.desktop/unix/native/common/java2d/x11/X11SurfaceData.c index 515923268ecd..f1584dcddf83 100644 --- a/src/java.desktop/unix/native/common/java2d/x11/X11SurfaceData.c +++ b/src/java.desktop/unix/native/common/java2d/x11/X11SurfaceData.c @@ -1703,3 +1703,90 @@ Java_sun_java2d_x11_XSurfaceData_XSetGraphicsExposures XSetGraphicsExposures(awt_display, (GC) xgc, needExposures ? True : False); #endif /* !HEADLESS */ } + +/* + * Class: sun_java2d_x11_X11SurfaceData + * Method: loadNativeRasterWithRects + * Signature: + */ +JNIEXPORT jboolean JNICALL +Java_sun_java2d_x11_XSurfaceData_loadNativeRasterWithRects + (JNIEnv *env, jclass clazz, + jlong sdops, jlong pRaster, jint width, jint height, jlong pRects, jint rectsCount) +{ + SurfaceDataOps *dstOps = (SurfaceDataOps *)sdops; + if (dstOps == NULL || pRaster == 0) { + J2dRlsTraceLn(J2D_TRACE_ERROR, "XSurfaceData_loadNativeRasterWithRects: params are null"); + return JNI_FALSE; + } + + if (pRects == 0 || rectsCount < 1) { + SurfaceDataRasInfo dstInfo; + memset(&dstInfo, 0, sizeof(SurfaceDataRasInfo)); + dstInfo.bounds.x1 = 0; + dstInfo.bounds.y1 = 0; + dstInfo.bounds.x2 = width; + dstInfo.bounds.y2 = height; + + if (dstOps->Lock(env, dstOps, &dstInfo, SD_LOCK_WRITE) != SD_SUCCESS) { + J2dRlsTraceLn(J2D_TRACE_ERROR, "XSurfaceData_loadNativeRasterWithRects: can't lock dest."); + return JNI_FALSE; + } + + dstOps->GetRasInfo(env, dstOps, &dstInfo); + if (dstInfo.rasBase) { + J2dTraceLn(J2D_TRACE_VERBOSE, "XSurfaceData_loadNativeRasterWithRects: copy whole memory."); + memcpy(dstInfo.rasBase, (void *) pRaster, width * height * 4); + } else { + J2dRlsTraceLn(J2D_TRACE_ERROR, "XSurfaceData_loadNativeRasterWithRects: can't get pointer of dest raster."); + } + + SurfaceData_InvokeRelease(env, dstOps, &dstInfo); + SurfaceData_InvokeUnlock(env, dstOps, &dstInfo); + } else { + int32_t *pr = (int32_t *) pRects; + for (int c = 0; c < rectsCount; ++c) { + int32_t x = *(pr++); + int32_t y = *(pr++); + int32_t w = *(pr++); + int32_t h = *(pr++); + + SurfaceDataRasInfo dstInfo; + memset(&dstInfo, 0, sizeof(SurfaceDataRasInfo)); + dstInfo.bounds.x1 = x; + dstInfo.bounds.y1 = y; + dstInfo.bounds.x2 = x + w; + dstInfo.bounds.y2 = y + h; + + if (dstOps->Lock(env, dstOps, &dstInfo, SD_LOCK_WRITE) != SD_SUCCESS) { + J2dRlsTraceLn(J2D_TRACE_ERROR, "XSurfaceData_loadNativeRasterWithRects: can't lock dest rect."); + return JNI_FALSE; + } + + dstOps->GetRasInfo(env, dstOps, &dstInfo); + if (dstInfo.rasBase) { + char* pSrc = (char*)PtrCoord(pRaster, x, 4, y, width*4); + char* pDst = (char*)PtrCoord(dstInfo.rasBase, x, dstInfo.pixelStride, y, dstInfo.scanStride); + if (dstInfo.scanStride == width*4) { + J2dTraceLn4(J2D_TRACE_VERBOSE, "XSurfaceData_loadNativeRasterWithRects: copy rect %d,%d - %d,%d [FAST]", x, y, w, h); + memcpy(pDst, pSrc, width*h*4); + } else { + J2dTraceLn4(J2D_TRACE_VERBOSE, "XSurfaceData_loadNativeRasterWithRects: copy rect %d,%d - %d,%d [line by line]", x, y, w, h); + for (int line = 0; line < h; ++line) { + memcpy(pDst, pSrc, w*4); + pSrc += width*4; + pDst += dstInfo.scanStride; + } + } + SurfaceData_InvokeRelease(env, dstOps, &dstInfo); + } else { + J2dRlsTraceLn(J2D_TRACE_ERROR, "XSurfaceData_loadNativeRasterWithRects: can't get pointer of dest raster (rect)."); + } + + SurfaceData_InvokeUnlock(env, dstOps, &dstInfo); + } + } + + return JNI_TRUE; +} + diff --git a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java index 425209dcae38..5ec6f2d9f8a3 100644 --- a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java +++ b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java @@ -1023,4 +1023,32 @@ public class D3DSurfaceData extends SurfaceData implements AccelSurface { */ public static native boolean updateWindowAccelImpl(long pd3dsd, long pData, int w, int h); + + /** + * Loads native image raster into surface. + * + * @param pRaster native pointer image raster with 8-bit RGBA color components packed into integer pixels. + * Note: The color data in this image is considered to be premultiplied with alpha. + * @param width width of image in pixels + * @param height height of image in pixels + * @param pRects native pointer to array of "dirty" rects, each rect is a sequence of four 32-bit integers: x, y, width, heigth + * Note: can be null (then whole image used) + * @param rectsCount count of "dirty" rects (if 0 then whole image used) + */ + @Override + protected void loadNativeRaster(long pRaster, int width, int height, long pRects, int rectsCount) { + D3DRenderQueue rq = D3DRenderQueue.getInstance(); + rq.lock(); + try { + // make sure we have a current context before uploading + // the sysmem data to the texture object + D3DContext.setScratchSurface(getContext()); + rq.flushAndInvokeNow(() -> loadNativeRasterWithRects(getNativeOps(), pRaster, width, height, pRects, rectsCount)); + } finally { + rq.unlock(); + } + markDirty(); + } + + private static native boolean loadNativeRasterWithRects(long pData, long pRaster, int width, int height, long pRects, int rectsCount); } diff --git a/src/java.desktop/windows/native/libawt/java2d/d3d/D3DSurfaceData.cpp b/src/java.desktop/windows/native/libawt/java2d/d3d/D3DSurfaceData.cpp index 9732d4d046b8..af5702f3fd61 100644 --- a/src/java.desktop/windows/native/libawt/java2d/d3d/D3DSurfaceData.cpp +++ b/src/java.desktop/windows/native/libawt/java2d/d3d/D3DSurfaceData.cpp @@ -25,6 +25,7 @@ #include "D3DPipeline.h" #include +#include #include "D3DSurfaceData.h" #include "D3DPipelineManager.h" #include "Trace.h" @@ -32,7 +33,18 @@ #include "awt_Window.h" #include "awt_BitmapUtil.h" #include "D3DRenderQueue.h" +#include "D3DBlitLoops.h" +#include "GraphicsPrimitiveMgr.h" +#include "IntArgb.h" +#include "IntArgbPre.h" +#include "IntRgb.h" +#include "IntBgr.h" + +extern "C" BlitFunc IntArgbToIntArgbPreConvert; +extern "C" BlitFunc IntArgbPreToIntArgbConvert; +extern "C" BlitFunc IntArgbBmToIntArgbConvert; +extern "C" BlitFunc IntRgbToIntArgbConvert; // REMIND: move to awt_Component.h extern "C" HWND AwtComponent_GetHWnd(JNIEnv *env, jlong pData); @@ -163,6 +175,134 @@ D3DSD_Unlock(JNIEnv *env, JNU_ThrowInternalError(env, "D3DSD_Unlock not implemented!"); } +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +jboolean loadNativeRasterWithRectsImpl( + D3DSDOps * d3dsdo, jlong pRaster, jint width, jint height, + jlong pRects, jint rectsCount +) { + D3DPipelineManager * pMgr = D3DPipelineManager::GetInstance(); + if (d3dsdo == NULL || d3dsdo->pResource == NULL || pMgr == NULL || pRaster == NULL) { + J2dTraceLn(J2D_TRACE_ERROR, "D3DSurfaceData_loadNativeRasterWithRects: null param."); + return JNI_FALSE; + } + + J2dTraceLn3(J2D_TRACE_VERBOSE, "D3DSurfaceData_loadNativeRasterWithRects: ops=%p r=%p rCount=%d\n", (void*)d3dsdo, (void*)pRaster, rectsCount); + + HRESULT res; + D3DContext *pCtx; + if (FAILED(res = pMgr->GetD3DContext(d3dsdo->adapter, &pCtx))) { + J2dTraceLn(J2D_TRACE_ERROR, "D3DSurfaceData_loadNativeRasterWithRects: failed GetD3DContext."); + return JNI_FALSE; + } + + // + // Blit via tiles + // + + D3DResource *pBlitTextureRes = NULL; + res = pCtx->GetResourceManager()->GetBlitTexture(&pBlitTextureRes); + if (FAILED(res)) { + J2dTraceLn(J2D_TRACE_ERROR, "D3DSurfaceData_loadNativeRasterWithRects: failed GetBlitTexture."); + return JNI_FALSE; + } + + IDirect3DSurface9 *pBlitSurface = pBlitTextureRes->GetSurface(); + IDirect3DTexture9 *pBlitTexture = pBlitTextureRes->GetTexture(); + D3DSURFACE_DESC *pBlitDesc = pBlitTextureRes->GetDesc(); + + res = pCtx->BeginScene(STATE_TEXTUREOP); + if (FAILED(res)) { + J2dTraceLn(J2D_TRACE_ERROR, "D3DSurfaceData_loadNativeRasterWithRects: failed BeginScene."); + return JNI_FALSE; + } + res = pCtx->SetTexture(pBlitTexture); + if (FAILED(res)) { + J2dTraceLn(J2D_TRACE_ERROR, "D3DSurfaceData_loadNativeRasterWithRects: failed SetTexture."); + return JNI_FALSE; + } + + IDirect3DDevice9 *pd3dDevice = pCtx->Get3DDevice(); + pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_NONE); + pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_NONE); + pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + + SurfaceDataRasInfo srcInfo; + ZeroMemory(&srcInfo, sizeof(SurfaceDataRasInfo)); + srcInfo.bounds.x1 = 0; + srcInfo.bounds.y1 = 0; + srcInfo.bounds.x2 = width; + srcInfo.bounds.y2 = height; + srcInfo.scanStride = width*4; + srcInfo.pixelStride = 4; + srcInfo.rasBase = (void*)pRaster; + srcInfo.pixelBitOffset = 0; + + const jint tw = pBlitDesc->Width; + const jint th = pBlitDesc->Height; + jint sy, dy; + jint sx, dx; + for (sy = 0, dy = 0; sy < height; sy += th, dy += th) { + jint sh = ((sy + th) > height) ? (height - sy) : th; + jint dh = ((dy + th) > height) ? (height - dy) : th; + + for (sx = 0, dx = 0; sx < width; sx += tw, dx += tw) { + jint sw = ((sx + tw) > width) ? (width - sx) : tw; + jint dw = ((dx + tw) > width) ? (width - dx) : tw; + + if (pRects == 0 || rectsCount < 1) { + //fprintf(stderr, "D3D_loadNativeRasterWithRects: do full copy of tile\n"); + D3DBL_CopyImageToIntXrgbSurface(&srcInfo, ST_INT_ARGB, pBlitTextureRes, sx, sy, sw, sh, 0, 0); + const double tx1 = ((double)sw) / tw; + const double ty1 = ((double)sh) / th; + res = pCtx->pVCacher->DrawTexture((float)dx, (float)dy, (float)(dx+dw), (float)(dy+dh), + 0.0f, 0.0f, (float)tx1, (float)ty1); + } else { + int32_t *pr = (int32_t *) pRects; + for (int c = 0; c < rectsCount; ++c) { + const int32_t rx = *(pr++); + const int32_t ry = *(pr++); + const int32_t rw = *(pr++); + const int32_t rh = *(pr++); + // Check intersection with tile. + if (sx + sw <= rx || sy + sh <= ry || rx + rw <= sx || rx + rw <= sx) + continue; + + // Calc intersection rect. + const int32_t rcX0 = MAX(sx, rx); + const int32_t rcY0 = MAX(sy, ry); + const int32_t rcX1 = MIN(sx + sw, rx + rw); + const int32_t rcY1 = MIN(sy + sh, ry + rh); + const int32_t rectW = rcX1 - rcX0; + const int32_t rectH = rcY1 - rcY0; + const int32_t relX0 = rcX0 - sx; + const int32_t relY0 = rcY0 - sy; + const int32_t relX1 = rcX1 - sx; + const int32_t relY1 = rcY1 - sy; + + // Blit. + D3DBL_CopyImageToIntXrgbSurface(&srcInfo, ST_INT_ARGB, pBlitTextureRes, rcX0, rcY0, rectW, rectH, relX0, relY0); + + // Render. + const double tx0 = ((double)relX0) / tw; + const double ty0 = ((double)relY0) / th; + const double tx1 = ((double)relX1) / tw; + const double ty1 = ((double)relY1) / th; + res = pCtx->pVCacher->DrawTexture( + (float)dx + relX0, (float)dy + relY0, (float)(dx + relX1), (float)(dy + relY1), + (float)tx0, (float)ty0, (float)tx1, (float)ty1); + } + } + + res = pCtx->pVCacher->Render(); + } + } + + return JNI_TRUE; +} + // ------------ D3DSurfaceData's JNI methods ---------------- @@ -636,4 +776,17 @@ JNICALL Java_sun_java2d_d3d_D3DSurfaceData_updateWindowAccelImpl return JNI_TRUE; } + + +/* + * Class: sun_java2d_d3d_D3DSurfaceData + * Method: loadNativeRasterWithRects + * Signature: + */ +JNIEXPORT +jboolean JNICALL Java_sun_java2d_d3d_D3DSurfaceData_loadNativeRasterWithRects + (JNIEnv *env, jclass clazz, jlong pData, jlong pRaster, jint width, jint height, jlong pRects, + jint rectsCount) { + return loadNativeRasterWithRectsImpl((D3DSDOps *) jlong_to_ptr(pData), pRaster, width, height, pRects, rectsCount); } +} // namespace extern C \ No newline at end of file diff --git a/src/jetbrains.api/src/com/jetbrains/NativeRasterLoader.java b/src/jetbrains.api/src/com/jetbrains/NativeRasterLoader.java new file mode 100644 index 000000000000..8ecba6a0c468 --- /dev/null +++ b/src/jetbrains.api/src/com/jetbrains/NativeRasterLoader.java @@ -0,0 +1,18 @@ +package com.jetbrains; + +import java.awt.image.VolatileImage; + +public interface NativeRasterLoader { + /** + * Loads native image raster into VolatileImage. + * + * @param pRaster native pointer image raster with 8-bit RGBA color components packed into integer pixels. + * Note: The color data in this image is considered to be premultiplied with alpha. + * @param width width of image in pixels + * @param height height of image in pixels + * @param pRects native pointer to array of "dirty" rects, each rect is a sequence of four 32-bit integers: x, y, width, heigth + * Note: can be null (then whole image used) + * @param rectsCount count of "dirty" rects (if 0 then whole image used) + */ + void loadNativeRaster(VolatileImage vi, long pRaster, int width, int height, long pRects, int rectsCount); +} \ No newline at end of file diff --git a/src/jetbrains.api/version.properties b/src/jetbrains.api/version.properties index b5015f2c2502..2a9536e3ef4a 100644 --- a/src/jetbrains.api/version.properties +++ b/src/jetbrains.api/version.properties @@ -6,9 +6,9 @@ # 2. When only new API is added, or some existing API was @Deprecated - increment MINOR, reset PATCH to 0 # 3. For major backwards incompatible API changes - increment MAJOR, reset MINOR and PATCH to 0 -VERSION = 1.9.0 +VERSION = 1.10.0 # Hash is used to track changes to jetbrains.api, so you would not forget to update version when needed. # When you make any changes, "make jbr-api" will fail and ask you to update hash and version number here. -HASH = 34E293D39C67B301086DDAD59EB9426 +HASH = 825E9B6832D82F59A0FFEAA4DA6F4A2