25
26 #include "awt.h"
27 #include <sun_java2d_windows_GDIBlitLoops.h>
28 #include "gdefs.h"
29 #include "Trace.h"
30 #include "GDIWindowSurfaceData.h"
31
32 static RGBQUAD *byteGrayPalette = NULL;
33
34 extern "C" {
35
36 typedef struct tagBitmapheader {
37 BITMAPINFOHEADER bmiHeader;
38 union {
39 DWORD dwMasks[3];
40 RGBQUAD palette[256];
41 } colors;
42 } BmiType;
43
44 /*
45 * Class: sun_java2d_windows_GDIBlitLoops
46 * Method: nativeBlit
47 * Signature: (Lsun/java2d/SurfaceData;Lsun/java2d/SurfaceData;IIIIIIZ)V
48 */
49 JNIEXPORT void JNICALL
50 Java_sun_java2d_windows_GDIBlitLoops_nativeBlit
51 (JNIEnv *env, jobject joSelf,
52 jobject srcData, jobject dstData,
53 jobject clip,
54 jint srcx, jint srcy,
55 jint dstx, jint dsty,
56 jint width, jint height,
57 jint rmask, jint gmask, jint bmask,
58 jboolean needLut)
59 {
60 J2dTraceLn(J2D_TRACE_INFO, "GDIBlitLoops_nativeBlit");
61
62 SurfaceDataRasInfo srcInfo;
63 SurfaceDataOps *srcOps = SurfaceData_GetOps(env, srcData);
64 GDIWinSDOps *dstOps = GDIWindowSurfaceData_GetOps(env, dstData);
110 // GetRasInfo implicitly calls GetPrimitiveArrayCritical
111 // and since GetDC uses JNI it needs to be called first.
112 HDC hDC = dstOps->GetDC(env, dstOps, 0, NULL, clip, NULL, 0);
113 if (hDC == NULL) {
114 SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
115 return;
116 }
117 srcOps->GetRasInfo(env, srcOps, &srcInfo);
118 if (srcInfo.rasBase == NULL) {
119 dstOps->ReleaseDC(env, dstOps, hDC);
120 SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
121 return;
122 }
123 void *rasBase = ((char *)srcInfo.rasBase) + srcInfo.scanStride * srcy +
124 srcInfo.pixelStride * srcx;
125
126 // If scanlines are DWORD-aligned (scanStride is a multiple of 4),
127 // then we can do the work much faster. This is due to a constraint
128 // in the way DIBs are structured and parsed by GDI
129 jboolean fastBlt = ((srcInfo.scanStride & 0x03) == 0);
130
131 bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
132 bmi.bmiHeader.biWidth = srcInfo.scanStride/srcInfo.pixelStride;
133 // fastBlt copies whole image in one call; else copy line-by-line
134 LONG dwHeight = srcInfo.bounds.y2 - srcInfo.bounds.y1;
135 bmi.bmiHeader.biHeight = (fastBlt) ? -dwHeight : -1;
136 bmi.bmiHeader.biPlanes = 1;
137 bmi.bmiHeader.biBitCount = (WORD)srcInfo.pixelStride * 8;
138 // 1,3,4 byte use BI_RGB, 2 byte use BI_BITFIELD...
139 // 4 byte _can_ use BI_BITFIELD, but this seems to cause a performance
140 // penalty. Since we only ever have one format (xrgb) for 32-bit
141 // images that enter this function, just use BI_RGB.
142 // Could do BI_RGB for 2-byte 555 format, but no perceived
143 // performance benefit.
144 bmi.bmiHeader.biCompression = (srcInfo.pixelStride != 2)
145 ? BI_RGB : BI_BITFIELDS;
146 bmi.bmiHeader.biSizeImage = (bmi.bmiHeader.biWidth * dwHeight *
147 srcInfo.pixelStride);
148 bmi.bmiHeader.biXPelsPerMeter = 0;
149 bmi.bmiHeader.biYPelsPerMeter = 0;
150 bmi.bmiHeader.biClrUsed = 0;
173 byteGrayPalette[i].rgbGreen = i;
174 byteGrayPalette[i].rgbBlue = i;
175 }
176 }
177 memcpy(bmi.colors.palette, byteGrayPalette, 256 * sizeof(RGBQUAD));
178 }
179 } else if (srcInfo.pixelStride == 2) {
180 // For 16-bit case, init the masks for the pixel depth
181 bmi.colors.dwMasks[0] = rmask;
182 bmi.colors.dwMasks[1] = gmask;
183 bmi.colors.dwMasks[2] = bmask;
184 }
185
186 if (fastBlt) {
187 // Window could go away at any time, leaving bits on the screen
188 // from this GDI call, so make sure window still exists
189 if (::IsWindowVisible(dstOps->window)) {
190 // Could also call StretchDIBits. Testing showed slight
191 // performance advantage of SetDIBits instead, so since we
192 // have no need of scaling, might as well use SetDIBits.
193 SetDIBitsToDevice(hDC, dstx, dsty, width, height,
194 0, 0, 0, height, rasBase,
195 (BITMAPINFO*)&bmi, DIB_RGB_COLORS);
196 }
197 } else {
198 // Source scanlines not DWORD-aligned - copy each scanline individually
199 for (int i = 0; i < height; i += 1) {
200 if (::IsWindowVisible(dstOps->window)) {
201 SetDIBitsToDevice(hDC, dstx, dsty+i, width, 1,
202 0, 0, 0, 1, rasBase,
203 (BITMAPINFO*)&bmi, DIB_RGB_COLORS);
204 rasBase = (void*)((char*)rasBase + srcInfo.scanStride);
205 } else {
206 break;
207 }
208 }
209 }
210 dstOps->ReleaseDC(env, dstOps, hDC);
211 SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
212 }
213 SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
214
215 return;
216 }
217
218 } // extern "C"
|
25
26 #include "awt.h"
27 #include <sun_java2d_windows_GDIBlitLoops.h>
28 #include "gdefs.h"
29 #include "Trace.h"
30 #include "GDIWindowSurfaceData.h"
31
32 static RGBQUAD *byteGrayPalette = NULL;
33
34 extern "C" {
35
36 typedef struct tagBitmapheader {
37 BITMAPINFOHEADER bmiHeader;
38 union {
39 DWORD dwMasks[3];
40 RGBQUAD palette[256];
41 } colors;
42 } BmiType;
43
44 /*
45 * Some GDI functions functions will fail if they operate on memory which spans
46 * virtual allocations as used by modern garbage collectors (ie ZGC).
47 * So if the call to SetDIBitsToDevice fails, we will re-try it on malloced
48 * memory rather than the pinned Java heap memory.
49 * Once Microsoft fix the GDI bug, the small performance penalty of this retry
50 * will be gone.
51 */
52 static void retryingSetDIBitsToDevice(
53 HDC hdc,
54 int xDest,
55 int yDest,
56 DWORD w,
57 DWORD h,
58 int xSrc,
59 int ySrc,
60 UINT StartScan,
61 UINT cLines,
62 const VOID *lpvBits,
63 BITMAPINFO *lpbmi,
64 UINT ColorUse) {
65
66 #ifdef DEBUG_PERF
67 LARGE_INTEGER ts1, ts2;
68 QueryPerformanceCounter(&ts1);
69 #endif
70
71 int ret =
72 SetDIBitsToDevice(hdc, xDest, yDest, w, h,
73 xSrc, ySrc, StartScan, cLines, lpvBits,
74 lpbmi, ColorUse);
75
76 if (ret != 0 || h == 0) {
77 #ifdef DEBUG_PERF
78 QueryPerformanceCounter(&ts2);
79 printf("success time: %zd\n", (ts2.QuadPart-ts1.QuadPart));
80 #endif
81 return;
82 }
83
84 size_t size = lpbmi->bmiHeader.biSizeImage;
85 void* imageData = NULL;
86 try {
87 imageData = safe_Malloc(size);
88 } catch (std::bad_alloc&) {
89 }
90 if (imageData == NULL) {
91 return;
92 }
93 memcpy(imageData, lpvBits, size); // this is the most expensive part.
94 SetDIBitsToDevice(hdc, xDest, yDest, w, h,
95 xSrc, ySrc, StartScan, cLines, imageData,
96 lpbmi, ColorUse);
97 free(imageData);
98
99 #ifdef DEBUG_PERF
100 QueryPerformanceCounter(&ts2);
101 printf("with retry time: %zd\n", (ts2.QuadPart-ts1.QuadPart));
102 #endif
103
104 };
105
106 /*
107 * Class: sun_java2d_windows_GDIBlitLoops
108 * Method: nativeBlit
109 * Signature: (Lsun/java2d/SurfaceData;Lsun/java2d/SurfaceData;IIIIIIZ)V
110 */
111 JNIEXPORT void JNICALL
112 Java_sun_java2d_windows_GDIBlitLoops_nativeBlit
113 (JNIEnv *env, jobject joSelf,
114 jobject srcData, jobject dstData,
115 jobject clip,
116 jint srcx, jint srcy,
117 jint dstx, jint dsty,
118 jint width, jint height,
119 jint rmask, jint gmask, jint bmask,
120 jboolean needLut)
121 {
122 J2dTraceLn(J2D_TRACE_INFO, "GDIBlitLoops_nativeBlit");
123
124 SurfaceDataRasInfo srcInfo;
125 SurfaceDataOps *srcOps = SurfaceData_GetOps(env, srcData);
126 GDIWinSDOps *dstOps = GDIWindowSurfaceData_GetOps(env, dstData);
172 // GetRasInfo implicitly calls GetPrimitiveArrayCritical
173 // and since GetDC uses JNI it needs to be called first.
174 HDC hDC = dstOps->GetDC(env, dstOps, 0, NULL, clip, NULL, 0);
175 if (hDC == NULL) {
176 SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
177 return;
178 }
179 srcOps->GetRasInfo(env, srcOps, &srcInfo);
180 if (srcInfo.rasBase == NULL) {
181 dstOps->ReleaseDC(env, dstOps, hDC);
182 SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
183 return;
184 }
185 void *rasBase = ((char *)srcInfo.rasBase) + srcInfo.scanStride * srcy +
186 srcInfo.pixelStride * srcx;
187
188 // If scanlines are DWORD-aligned (scanStride is a multiple of 4),
189 // then we can do the work much faster. This is due to a constraint
190 // in the way DIBs are structured and parsed by GDI
191 jboolean fastBlt = ((srcInfo.scanStride & 0x03) == 0);
192 bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
193 bmi.bmiHeader.biWidth = srcInfo.scanStride/srcInfo.pixelStride;
194 // fastBlt copies whole image in one call; else copy line-by-line
195 LONG dwHeight = srcInfo.bounds.y2 - srcInfo.bounds.y1;
196 bmi.bmiHeader.biHeight = (fastBlt) ? -dwHeight : -1;
197 bmi.bmiHeader.biPlanes = 1;
198 bmi.bmiHeader.biBitCount = (WORD)srcInfo.pixelStride * 8;
199 // 1,3,4 byte use BI_RGB, 2 byte use BI_BITFIELD...
200 // 4 byte _can_ use BI_BITFIELD, but this seems to cause a performance
201 // penalty. Since we only ever have one format (xrgb) for 32-bit
202 // images that enter this function, just use BI_RGB.
203 // Could do BI_RGB for 2-byte 555 format, but no perceived
204 // performance benefit.
205 bmi.bmiHeader.biCompression = (srcInfo.pixelStride != 2)
206 ? BI_RGB : BI_BITFIELDS;
207 bmi.bmiHeader.biSizeImage = (bmi.bmiHeader.biWidth * dwHeight *
208 srcInfo.pixelStride);
209 bmi.bmiHeader.biXPelsPerMeter = 0;
210 bmi.bmiHeader.biYPelsPerMeter = 0;
211 bmi.bmiHeader.biClrUsed = 0;
234 byteGrayPalette[i].rgbGreen = i;
235 byteGrayPalette[i].rgbBlue = i;
236 }
237 }
238 memcpy(bmi.colors.palette, byteGrayPalette, 256 * sizeof(RGBQUAD));
239 }
240 } else if (srcInfo.pixelStride == 2) {
241 // For 16-bit case, init the masks for the pixel depth
242 bmi.colors.dwMasks[0] = rmask;
243 bmi.colors.dwMasks[1] = gmask;
244 bmi.colors.dwMasks[2] = bmask;
245 }
246
247 if (fastBlt) {
248 // Window could go away at any time, leaving bits on the screen
249 // from this GDI call, so make sure window still exists
250 if (::IsWindowVisible(dstOps->window)) {
251 // Could also call StretchDIBits. Testing showed slight
252 // performance advantage of SetDIBits instead, so since we
253 // have no need of scaling, might as well use SetDIBits.
254 retryingSetDIBitsToDevice(hDC, dstx, dsty, width, height,
255 0, 0, 0, height, rasBase,
256 (BITMAPINFO*)&bmi, DIB_RGB_COLORS);
257 }
258 } else {
259 // Source scanlines not DWORD-aligned - copy each scanline individually
260 for (int i = 0; i < height; i += 1) {
261 if (::IsWindowVisible(dstOps->window)) {
262 retryingSetDIBitsToDevice(hDC, dstx, dsty+i, width, 1,
263 0, 0, 0, 1, rasBase,
264 (BITMAPINFO*)&bmi, DIB_RGB_COLORS);
265 rasBase = (void*)((char*)rasBase + srcInfo.scanStride);
266 } else {
267 break;
268 }
269 }
270 }
271 dstOps->ReleaseDC(env, dstOps, hDC);
272 SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
273 }
274 SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
275
276 return;
277 }
278
279 } // extern "C"
|