Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/native/sun/java2d/opengl/OGLBlitLoops.c
38918 views
1
/*
2
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
#ifndef HEADLESS
27
28
#include <jni.h>
29
#include <jlong.h>
30
31
#include "SurfaceData.h"
32
#include "OGLBlitLoops.h"
33
#include "OGLRenderQueue.h"
34
#include "OGLSurfaceData.h"
35
#include "GraphicsPrimitiveMgr.h"
36
37
#include <stdlib.h> // malloc
38
#include <string.h> // memcpy
39
#include "IntArgbPre.h"
40
41
extern OGLPixelFormat PixelFormats[];
42
43
/**
44
* Inner loop used for copying a source OpenGL "Surface" (window, pbuffer,
45
* etc.) to a destination OpenGL "Surface". Note that the same surface can
46
* be used as both the source and destination, as is the case in a copyArea()
47
* operation. This method is invoked from OGLBlitLoops_IsoBlit() as well as
48
* OGLBlitLoops_CopyArea().
49
*
50
* The standard glCopyPixels() mechanism is used to copy the source region
51
* into the destination region. If the regions have different dimensions,
52
* the source will be scaled into the destination as appropriate (only
53
* nearest neighbor filtering will be applied for simple scale operations).
54
*/
55
static void
56
OGLBlitSurfaceToSurface(OGLContext *oglc, OGLSDOps *srcOps, OGLSDOps *dstOps,
57
jint sx1, jint sy1, jint sx2, jint sy2,
58
jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
59
{
60
GLfloat scalex, scaley;
61
jint srcw = sx2 - sx1;
62
jint srch = sy2 - sy1;
63
64
scalex = ((GLfloat)(dx2-dx1)) / srcw;
65
scaley = ((GLfloat)(dy2-dy1)) / srch;
66
67
// the following lines account for the fact that glCopyPixels() copies a
68
// region whose lower-left corner is at (x,y), but the source parameters
69
// (sx1,sy1) we are given here point to the upper-left corner of the
70
// source region... so here we play with the sy1 and dy1 parameters so
71
// that they point to the lower-left corners of the regions...
72
sx1 = srcOps->xOffset + sx1;
73
sy1 = srcOps->yOffset + srcOps->height - sy2;
74
dy1 = dy2;
75
76
if (oglc->extraAlpha != 1.0f) {
77
OGLContext_SetExtraAlpha(oglc->extraAlpha);
78
}
79
80
// see OGLBlitSwToSurface() for more info on the following two lines
81
j2d_glRasterPos2i(0, 0);
82
j2d_glBitmap(0, 0, 0, 0, (GLfloat)dx1, (GLfloat)-dy1, NULL);
83
84
if (scalex == 1.0f && scaley == 1.0f) {
85
j2d_glCopyPixels(sx1, sy1, srcw, srch, GL_COLOR);
86
} else {
87
j2d_glPixelZoom(scalex, scaley);
88
j2d_glCopyPixels(sx1, sy1, srcw, srch, GL_COLOR);
89
j2d_glPixelZoom(1.0f, 1.0f);
90
}
91
92
if (oglc->extraAlpha != 1.0f) {
93
OGLContext_SetExtraAlpha(1.0f);
94
}
95
}
96
97
/**
98
* Inner loop used for copying a source OpenGL "Texture" to a destination
99
* OpenGL "Surface". This method is invoked from OGLBlitLoops_IsoBlit().
100
*
101
* This method will copy, scale, or transform the source texture into the
102
* destination depending on the transform state, as established in
103
* and OGLContext_SetTransform(). If the source texture is
104
* transformed in any way when rendered into the destination, the filtering
105
* method applied is determined by the hint parameter (can be GL_NEAREST or
106
* GL_LINEAR).
107
*/
108
static void
109
OGLBlitTextureToSurface(OGLContext *oglc,
110
OGLSDOps *srcOps, OGLSDOps *dstOps,
111
jboolean rtt, jint hint,
112
jint sx1, jint sy1, jint sx2, jint sy2,
113
jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
114
{
115
GLdouble tx1, ty1, tx2, ty2;
116
117
if (rtt) {
118
/*
119
* The source is a render-to-texture surface. These surfaces differ
120
* from regular texture objects in that the bottom scanline (of
121
* the actual image content) coincides with the top edge of the
122
* texture object. Therefore, we need to adjust the sy1/sy2
123
* coordinates relative to the top scanline of the image content.
124
*
125
* In texture coordinates, the top-left corner of the image content
126
* would be at:
127
* (0.0, (imgHeight/texHeight))
128
* while the bottom-right corner corresponds to:
129
* ((imgWidth/texWidth), 0.0)
130
*/
131
sy1 = srcOps->height - sy1;
132
sy2 = srcOps->height - sy2;
133
}
134
135
if (srcOps->textureTarget == GL_TEXTURE_RECTANGLE_ARB) {
136
// The GL_ARB_texture_rectangle extension requires that we specify
137
// texture coordinates in the range [0,srcw] and [0,srch] instead of
138
// [0,1] as we would normally do in the case of GL_TEXTURE_2D
139
tx1 = (GLdouble)sx1;
140
ty1 = (GLdouble)sy1;
141
tx2 = (GLdouble)sx2;
142
ty2 = (GLdouble)sy2;
143
} else {
144
// Otherwise we need to convert the source bounds into the range [0,1]
145
tx1 = ((GLdouble)sx1) / srcOps->textureWidth;
146
ty1 = ((GLdouble)sy1) / srcOps->textureHeight;
147
tx2 = ((GLdouble)sx2) / srcOps->textureWidth;
148
ty2 = ((GLdouble)sy2) / srcOps->textureHeight;
149
}
150
151
// Note that we call CHECK_PREVIOUS_OP(texTarget) in IsoBlit(), which
152
// will call glEnable(texTarget) as necessary.
153
j2d_glBindTexture(srcOps->textureTarget, srcOps->textureID);
154
OGLC_UPDATE_TEXTURE_FUNCTION(oglc, GL_MODULATE);
155
OGLSD_UPDATE_TEXTURE_FILTER(srcOps, hint);
156
157
j2d_glBegin(GL_QUADS);
158
j2d_glTexCoord2d(tx1, ty1); j2d_glVertex2d(dx1, dy1);
159
j2d_glTexCoord2d(tx2, ty1); j2d_glVertex2d(dx2, dy1);
160
j2d_glTexCoord2d(tx2, ty2); j2d_glVertex2d(dx2, dy2);
161
j2d_glTexCoord2d(tx1, ty2); j2d_glVertex2d(dx1, dy2);
162
j2d_glEnd();
163
}
164
165
/**
166
* Inner loop used for copying a source system memory ("Sw") surface to a
167
* destination OpenGL "Surface". This method is invoked from
168
* OGLBlitLoops_Blit().
169
*
170
* The standard glDrawPixels() mechanism is used to copy the source region
171
* into the destination region. If the regions have different
172
* dimensions, the source will be scaled into the destination
173
* as appropriate (only nearest neighbor filtering will be applied for simple
174
* scale operations).
175
*/
176
static void
177
OGLBlitSwToSurface(OGLContext *oglc, SurfaceDataRasInfo *srcInfo,
178
OGLPixelFormat *pf,
179
jint sx1, jint sy1, jint sx2, jint sy2,
180
jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
181
{
182
GLfloat scalex, scaley;
183
GLvoid *pSrc;
184
185
scalex = ((GLfloat)(dx2-dx1)) / (sx2-sx1);
186
scaley = ((GLfloat)(dy2-dy1)) / (sy2-sy1);
187
188
if (oglc->extraAlpha != 1.0f) {
189
OGLContext_SetExtraAlpha(oglc->extraAlpha);
190
}
191
if (!pf->hasAlpha) {
192
// if the source surface does not have an alpha channel,
193
// we need to ensure that the alpha values are forced to
194
// the current extra alpha value (see OGLContext_SetExtraAlpha()
195
// for more information)
196
j2d_glPixelTransferf(GL_ALPHA_SCALE, 0.0f);
197
j2d_glPixelTransferf(GL_ALPHA_BIAS, oglc->extraAlpha);
198
}
199
200
// This is a rather intriguing (yet totally valid) hack... If we were to
201
// specify a raster position that is outside the surface bounds, the raster
202
// position would be invalid and nothing would be rendered. However, we
203
// can use a widely known trick to move the raster position outside the
204
// surface bounds while maintaining its status as valid. The following
205
// call to glBitmap() renders a no-op bitmap, but offsets the current
206
// raster position from (0,0) to the desired location of (dx1,-dy1)...
207
j2d_glRasterPos2i(0, 0);
208
j2d_glBitmap(0, 0, 0, 0, (GLfloat)dx1, (GLfloat)-dy1, NULL);
209
210
j2d_glPixelZoom(scalex, -scaley);
211
212
pSrc = PtrCoord(srcInfo->rasBase, sx1, srcInfo->pixelStride,
213
sy1, srcInfo->scanStride);
214
215
// in case pixel stride is not a multiple of scanline stride the copy
216
// has to be done line by line (see 6207877)
217
if (srcInfo->scanStride % srcInfo->pixelStride != 0) {
218
jint width = sx2-sx1;
219
jint height = sy2-sy1;
220
while (height > 0) {
221
j2d_glDrawPixels(width, 1, pf->format, pf->type, pSrc);
222
j2d_glBitmap(0, 0, 0, 0, (GLfloat)0, (GLfloat)-scaley, NULL);
223
pSrc = PtrAddBytes(pSrc, srcInfo->scanStride);
224
height--;
225
}
226
} else {
227
j2d_glDrawPixels(sx2-sx1, sy2-sy1, pf->format, pf->type, pSrc);
228
}
229
230
j2d_glPixelZoom(1.0, 1.0);
231
232
if (oglc->extraAlpha != 1.0f) {
233
OGLContext_SetExtraAlpha(1.0f);
234
}
235
if (!pf->hasAlpha) {
236
// restore scale/bias to their original values
237
j2d_glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
238
j2d_glPixelTransferf(GL_ALPHA_BIAS, 0.0f);
239
}
240
}
241
242
/**
243
* Inner loop used for copying a source system memory ("Sw") surface or
244
* OpenGL "Surface" to a destination OpenGL "Surface", using an OpenGL texture
245
* tile as an intermediate surface. This method is invoked from
246
* OGLBlitLoops_Blit() for "Sw" surfaces and OGLBlitLoops_IsoBlit() for
247
* "Surface" surfaces.
248
*
249
* This method is used to transform the source surface into the destination.
250
* Pixel rectangles cannot be arbitrarily transformed (without the
251
* GL_EXT_pixel_transform extension, which is not supported on most modern
252
* hardware). However, texture mapped quads do respect the GL_MODELVIEW
253
* transform matrix, so we use textures here to perform the transform
254
* operation. This method uses a tile-based approach in which a small
255
* subregion of the source surface is copied into a cached texture tile. The
256
* texture tile is then mapped into the appropriate location in the
257
* destination surface.
258
*
259
* REMIND: this only works well using GL_NEAREST for the filtering mode
260
* (GL_LINEAR causes visible stitching problems between tiles,
261
* but this can be fixed by making use of texture borders)
262
*/
263
static void
264
OGLBlitToSurfaceViaTexture(OGLContext *oglc, SurfaceDataRasInfo *srcInfo,
265
OGLPixelFormat *pf, OGLSDOps *srcOps,
266
jboolean swsurface, jint hint,
267
jint sx1, jint sy1, jint sx2, jint sy2,
268
jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
269
{
270
GLdouble tx1, ty1, tx2, ty2;
271
GLdouble dx, dy, dw, dh, cdw, cdh;
272
jint tw, th;
273
jint sx, sy, sw, sh;
274
GLint glhint = (hint == OGLSD_XFORM_BILINEAR) ? GL_LINEAR : GL_NEAREST;
275
jboolean adjustAlpha = (pf != NULL && !pf->hasAlpha);
276
jboolean slowPath;
277
278
if (oglc->blitTextureID == 0) {
279
if (!OGLContext_InitBlitTileTexture(oglc)) {
280
J2dRlsTraceLn(J2D_TRACE_ERROR,
281
"OGLBlitToSurfaceViaTexture: could not init blit tile");
282
return;
283
}
284
}
285
286
tx1 = 0.0f;
287
ty1 = 0.0f;
288
tw = OGLC_BLIT_TILE_SIZE;
289
th = OGLC_BLIT_TILE_SIZE;
290
cdw = (dx2-dx1) / (((GLdouble)(sx2-sx1)) / OGLC_BLIT_TILE_SIZE);
291
cdh = (dy2-dy1) / (((GLdouble)(sy2-sy1)) / OGLC_BLIT_TILE_SIZE);
292
293
j2d_glEnable(GL_TEXTURE_2D);
294
j2d_glBindTexture(GL_TEXTURE_2D, oglc->blitTextureID);
295
OGLC_UPDATE_TEXTURE_FUNCTION(oglc, GL_MODULATE);
296
j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, glhint);
297
j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, glhint);
298
299
if (adjustAlpha) {
300
// if the source surface does not have an alpha channel,
301
// we need to ensure that the alpha values are forced to 1.0f
302
j2d_glPixelTransferf(GL_ALPHA_SCALE, 0.0f);
303
j2d_glPixelTransferf(GL_ALPHA_BIAS, 1.0f);
304
}
305
306
// in case pixel stride is not a multiple of scanline stride the copy
307
// has to be done line by line (see 6207877)
308
slowPath = srcInfo->scanStride % srcInfo->pixelStride != 0;
309
310
for (sy = sy1, dy = dy1; sy < sy2; sy += th, dy += cdh) {
311
sh = ((sy + th) > sy2) ? (sy2 - sy) : th;
312
dh = ((dy + cdh) > dy2) ? (dy2 - dy) : cdh;
313
314
for (sx = sx1, dx = dx1; sx < sx2; sx += tw, dx += cdw) {
315
sw = ((sx + tw) > sx2) ? (sx2 - sx) : tw;
316
dw = ((dx + cdw) > dx2) ? (dx2 - dx) : cdw;
317
318
tx2 = ((GLdouble)sw) / tw;
319
ty2 = ((GLdouble)sh) / th;
320
321
if (swsurface) {
322
GLvoid *pSrc = PtrCoord(srcInfo->rasBase,
323
sx, srcInfo->pixelStride,
324
sy, srcInfo->scanStride);
325
if (slowPath) {
326
jint tmph = sh;
327
while (tmph > 0) {
328
j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,
329
0, sh - tmph, sw, 1,
330
pf->format, pf->type,
331
pSrc);
332
pSrc = PtrAddBytes(pSrc, srcInfo->scanStride);
333
tmph--;
334
}
335
} else {
336
j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,
337
0, 0, sw, sh,
338
pf->format, pf->type,
339
pSrc);
340
}
341
342
// the texture image is "right side up", so we align the
343
// upper-left texture corner with the upper-left quad corner
344
j2d_glBegin(GL_QUADS);
345
j2d_glTexCoord2d(tx1, ty1); j2d_glVertex2d(dx, dy);
346
j2d_glTexCoord2d(tx2, ty1); j2d_glVertex2d(dx + dw, dy);
347
j2d_glTexCoord2d(tx2, ty2); j2d_glVertex2d(dx + dw, dy + dh);
348
j2d_glTexCoord2d(tx1, ty2); j2d_glVertex2d(dx, dy + dh);
349
j2d_glEnd();
350
} else {
351
// this accounts for lower-left origin of the source region
352
jint newsx = srcOps->xOffset + sx;
353
jint newsy = srcOps->yOffset + srcOps->height - (sy + sh);
354
j2d_glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
355
0, 0, newsx, newsy, sw, sh);
356
357
// the texture image is "upside down" after the last step, so
358
// we align the bottom-left texture corner with the upper-left
359
// quad corner (and vice versa) to effectively flip the
360
// texture image
361
j2d_glBegin(GL_QUADS);
362
j2d_glTexCoord2d(tx1, ty2); j2d_glVertex2d(dx, dy);
363
j2d_glTexCoord2d(tx2, ty2); j2d_glVertex2d(dx + dw, dy);
364
j2d_glTexCoord2d(tx2, ty1); j2d_glVertex2d(dx + dw, dy + dh);
365
j2d_glTexCoord2d(tx1, ty1); j2d_glVertex2d(dx, dy + dh);
366
j2d_glEnd();
367
}
368
}
369
}
370
371
if (adjustAlpha) {
372
// restore scale/bias to their original values
373
j2d_glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
374
j2d_glPixelTransferf(GL_ALPHA_BIAS, 0.0f);
375
}
376
377
j2d_glDisable(GL_TEXTURE_2D);
378
}
379
380
/**
381
* Inner loop used for copying a source system memory ("Sw") surface to a
382
* destination OpenGL "Texture". This method is invoked from
383
* OGLBlitLoops_Blit().
384
*
385
* The source surface is effectively loaded into the OpenGL texture object,
386
* which must have already been initialized by OGLSD_initTexture(). Note
387
* that this method is only capable of copying the source surface into the
388
* destination surface (i.e. no scaling or general transform is allowed).
389
* This restriction should not be an issue as this method is only used
390
* currently to cache a static system memory image into an OpenGL texture in
391
* a hidden-acceleration situation.
392
*/
393
static void
394
OGLBlitSwToTexture(SurfaceDataRasInfo *srcInfo, OGLPixelFormat *pf,
395
OGLSDOps *dstOps,
396
jint dx1, jint dy1, jint dx2, jint dy2)
397
{
398
jboolean adjustAlpha = (pf != NULL && !pf->hasAlpha);
399
j2d_glBindTexture(dstOps->textureTarget, dstOps->textureID);
400
401
if (adjustAlpha) {
402
// if the source surface does not have an alpha channel,
403
// we need to ensure that the alpha values are forced to 1.0f
404
j2d_glPixelTransferf(GL_ALPHA_SCALE, 0.0f);
405
j2d_glPixelTransferf(GL_ALPHA_BIAS, 1.0f);
406
}
407
408
// in case pixel stride is not a multiple of scanline stride the copy
409
// has to be done line by line (see 6207877)
410
if (srcInfo->scanStride % srcInfo->pixelStride != 0) {
411
jint width = dx2 - dx1;
412
jint height = dy2 - dy1;
413
GLvoid *pSrc = srcInfo->rasBase;
414
415
while (height > 0) {
416
j2d_glTexSubImage2D(dstOps->textureTarget, 0,
417
dx1, dy2 - height, width, 1,
418
pf->format, pf->type, pSrc);
419
pSrc = PtrAddBytes(pSrc, srcInfo->scanStride);
420
height--;
421
}
422
} else {
423
j2d_glTexSubImage2D(dstOps->textureTarget, 0,
424
dx1, dy1, dx2-dx1, dy2-dy1,
425
pf->format, pf->type, srcInfo->rasBase);
426
}
427
if (adjustAlpha) {
428
// restore scale/bias to their original values
429
j2d_glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
430
j2d_glPixelTransferf(GL_ALPHA_BIAS, 0.0f);
431
}
432
}
433
434
/**
435
* General blit method for copying a native OpenGL surface (of type "Surface"
436
* or "Texture") to another OpenGL "Surface". If texture is JNI_TRUE, this
437
* method will invoke the Texture->Surface inner loop; otherwise, one of the
438
* Surface->Surface inner loops will be invoked, depending on the transform
439
* state.
440
*
441
* REMIND: we can trick these blit methods into doing XOR simply by passing
442
* in the (pixel ^ xorpixel) as the pixel value and preceding the
443
* blit with a fillrect...
444
*/
445
void
446
OGLBlitLoops_IsoBlit(JNIEnv *env,
447
OGLContext *oglc, jlong pSrcOps, jlong pDstOps,
448
jboolean xform, jint hint,
449
jboolean texture, jboolean rtt,
450
jint sx1, jint sy1, jint sx2, jint sy2,
451
jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
452
{
453
OGLSDOps *srcOps = (OGLSDOps *)jlong_to_ptr(pSrcOps);
454
OGLSDOps *dstOps = (OGLSDOps *)jlong_to_ptr(pDstOps);
455
SurfaceDataRasInfo srcInfo;
456
jint sw = sx2 - sx1;
457
jint sh = sy2 - sy1;
458
jdouble dw = dx2 - dx1;
459
jdouble dh = dy2 - dy1;
460
461
J2dTraceLn(J2D_TRACE_INFO, "OGLBlitLoops_IsoBlit");
462
463
if (sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0) {
464
J2dTraceLn(J2D_TRACE_WARNING,
465
"OGLBlitLoops_IsoBlit: invalid dimensions");
466
return;
467
}
468
469
RETURN_IF_NULL(srcOps);
470
RETURN_IF_NULL(dstOps);
471
RETURN_IF_NULL(oglc);
472
473
srcInfo.bounds.x1 = sx1;
474
srcInfo.bounds.y1 = sy1;
475
srcInfo.bounds.x2 = sx2;
476
srcInfo.bounds.y2 = sy2;
477
478
SurfaceData_IntersectBoundsXYXY(&srcInfo.bounds,
479
0, 0, srcOps->width, srcOps->height);
480
481
if (srcInfo.bounds.x2 > srcInfo.bounds.x1 &&
482
srcInfo.bounds.y2 > srcInfo.bounds.y1)
483
{
484
if (srcInfo.bounds.x1 != sx1) {
485
dx1 += (srcInfo.bounds.x1 - sx1) * (dw / sw);
486
sx1 = srcInfo.bounds.x1;
487
}
488
if (srcInfo.bounds.y1 != sy1) {
489
dy1 += (srcInfo.bounds.y1 - sy1) * (dh / sh);
490
sy1 = srcInfo.bounds.y1;
491
}
492
if (srcInfo.bounds.x2 != sx2) {
493
dx2 += (srcInfo.bounds.x2 - sx2) * (dw / sw);
494
sx2 = srcInfo.bounds.x2;
495
}
496
if (srcInfo.bounds.y2 != sy2) {
497
dy2 += (srcInfo.bounds.y2 - sy2) * (dh / sh);
498
sy2 = srcInfo.bounds.y2;
499
}
500
501
J2dTraceLn2(J2D_TRACE_VERBOSE, " texture=%d hint=%d", texture, hint);
502
J2dTraceLn4(J2D_TRACE_VERBOSE, " sx1=%d sy1=%d sx2=%d sy2=%d",
503
sx1, sy1, sx2, sy2);
504
J2dTraceLn4(J2D_TRACE_VERBOSE, " dx1=%f dy1=%f dx2=%f dy2=%f",
505
dx1, dy1, dx2, dy2);
506
507
if (texture) {
508
GLint glhint = (hint == OGLSD_XFORM_BILINEAR) ? GL_LINEAR :
509
GL_NEAREST;
510
CHECK_PREVIOUS_OP(srcOps->textureTarget);
511
OGLBlitTextureToSurface(oglc, srcOps, dstOps, rtt, glhint,
512
sx1, sy1, sx2, sy2,
513
dx1, dy1, dx2, dy2);
514
} else {
515
jboolean viaTexture;
516
if (xform) {
517
// we must use the via-texture codepath when there is a xform
518
viaTexture = JNI_TRUE;
519
} else {
520
// look at the vendor to see which codepath is faster
521
// (this has been empirically determined; see 5020009)
522
switch (OGLC_GET_VENDOR(oglc)) {
523
case OGLC_VENDOR_NVIDIA:
524
// the via-texture codepath tends to be faster when
525
// there is either a simple scale OR an extra alpha
526
viaTexture =
527
(sx2-sx1) != (jint)(dx2-dx1) ||
528
(sy2-sy1) != (jint)(dy2-dy1) ||
529
oglc->extraAlpha != 1.0f;
530
break;
531
532
case OGLC_VENDOR_ATI:
533
// the via-texture codepath tends to be faster only when
534
// there is an extra alpha involved (scaling or not)
535
viaTexture = (oglc->extraAlpha != 1.0f);
536
break;
537
538
default:
539
// just use the glCopyPixels() codepath
540
viaTexture = JNI_FALSE;
541
break;
542
}
543
}
544
545
RESET_PREVIOUS_OP();
546
if (viaTexture) {
547
OGLBlitToSurfaceViaTexture(oglc, &srcInfo, NULL, srcOps,
548
JNI_FALSE, hint,
549
sx1, sy1, sx2, sy2,
550
dx1, dy1, dx2, dy2);
551
} else {
552
OGLBlitSurfaceToSurface(oglc, srcOps, dstOps,
553
sx1, sy1, sx2, sy2,
554
dx1, dy1, dx2, dy2);
555
}
556
}
557
}
558
}
559
560
/**
561
* General blit method for copying a system memory ("Sw") surface to a native
562
* OpenGL surface (of type "Surface" or "Texture"). If texture is JNI_TRUE,
563
* this method will invoke the Sw->Texture inner loop; otherwise, one of the
564
* Sw->Surface inner loops will be invoked, depending on the transform state.
565
*/
566
void
567
OGLBlitLoops_Blit(JNIEnv *env,
568
OGLContext *oglc, jlong pSrcOps, jlong pDstOps,
569
jboolean xform, jint hint,
570
jint srctype, jboolean texture,
571
jint sx1, jint sy1, jint sx2, jint sy2,
572
jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
573
{
574
SurfaceDataOps *srcOps = (SurfaceDataOps *)jlong_to_ptr(pSrcOps);
575
OGLSDOps *dstOps = (OGLSDOps *)jlong_to_ptr(pDstOps);
576
SurfaceDataRasInfo srcInfo;
577
OGLPixelFormat pf = PixelFormats[srctype];
578
jint sw = sx2 - sx1;
579
jint sh = sy2 - sy1;
580
jdouble dw = dx2 - dx1;
581
jdouble dh = dy2 - dy1;
582
583
J2dTraceLn(J2D_TRACE_INFO, "OGLBlitLoops_Blit");
584
585
if (sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0 || srctype < 0) {
586
J2dTraceLn(J2D_TRACE_WARNING,
587
"OGLBlitLoops_Blit: invalid dimensions or srctype");
588
return;
589
}
590
591
RETURN_IF_NULL(srcOps);
592
RETURN_IF_NULL(dstOps);
593
RETURN_IF_NULL(oglc);
594
RESET_PREVIOUS_OP();
595
596
srcInfo.bounds.x1 = sx1;
597
srcInfo.bounds.y1 = sy1;
598
srcInfo.bounds.x2 = sx2;
599
srcInfo.bounds.y2 = sy2;
600
601
if (srcOps->Lock(env, srcOps, &srcInfo, SD_LOCK_READ) != SD_SUCCESS) {
602
J2dTraceLn(J2D_TRACE_WARNING,
603
"OGLBlitLoops_Blit: could not acquire lock");
604
return;
605
}
606
607
if (srcInfo.bounds.x2 > srcInfo.bounds.x1 &&
608
srcInfo.bounds.y2 > srcInfo.bounds.y1)
609
{
610
srcOps->GetRasInfo(env, srcOps, &srcInfo);
611
if (srcInfo.rasBase) {
612
if (srcInfo.bounds.x1 != sx1) {
613
dx1 += (srcInfo.bounds.x1 - sx1) * (dw / sw);
614
sx1 = srcInfo.bounds.x1;
615
}
616
if (srcInfo.bounds.y1 != sy1) {
617
dy1 += (srcInfo.bounds.y1 - sy1) * (dh / sh);
618
sy1 = srcInfo.bounds.y1;
619
}
620
if (srcInfo.bounds.x2 != sx2) {
621
dx2 += (srcInfo.bounds.x2 - sx2) * (dw / sw);
622
sx2 = srcInfo.bounds.x2;
623
}
624
if (srcInfo.bounds.y2 != sy2) {
625
dy2 += (srcInfo.bounds.y2 - sy2) * (dh / sh);
626
sy2 = srcInfo.bounds.y2;
627
}
628
629
J2dTraceLn3(J2D_TRACE_VERBOSE, " texture=%d srctype=%d hint=%d",
630
texture, srctype, hint);
631
J2dTraceLn4(J2D_TRACE_VERBOSE, " sx1=%d sy1=%d sx2=%d sy2=%d",
632
sx1, sy1, sx2, sy2);
633
J2dTraceLn4(J2D_TRACE_VERBOSE, " dx1=%f dy1=%f dx2=%f dy2=%f",
634
dx1, dy1, dx2, dy2);
635
636
// Note: we will calculate x/y positions in the raster manually
637
j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
638
j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
639
j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH,
640
srcInfo.scanStride / srcInfo.pixelStride);
641
j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, pf.alignment);
642
643
if (texture) {
644
// These coordinates will always be integers since we
645
// only ever do a straight copy from sw to texture.
646
// Thus these casts are "safe" - no loss of precision.
647
OGLBlitSwToTexture(&srcInfo, &pf, dstOps,
648
(jint)dx1, (jint)dy1, (jint)dx2, (jint)dy2);
649
} else {
650
jboolean viaTexture;
651
if (xform) {
652
// we must use the via-texture codepath when there
653
// is a xform
654
viaTexture = JNI_TRUE;
655
} else {
656
// look at the vendor to see which codepath is faster
657
// (this has been empirically determined; see 5020009)
658
switch (OGLC_GET_VENDOR(oglc)) {
659
case OGLC_VENDOR_NVIDIA:
660
// the via-texture codepath tends to be faster when
661
// there is either a simple scale OR an extra alpha
662
viaTexture =
663
(sx2-sx1) != (jint)(dx2-dx1) ||
664
(sy2-sy1) != (jint)(dy2-dy1) ||
665
oglc->extraAlpha != 1.0f;
666
break;
667
#ifdef MACOSX
668
case OGLC_VENDOR_ATI:
669
// see 8024461
670
viaTexture = JNI_TRUE;
671
break;
672
#endif
673
case OGLC_VENDOR_INTEL:
674
viaTexture = JNI_TRUE;
675
break;
676
default:
677
// just use the glDrawPixels() codepath
678
viaTexture = JNI_FALSE;
679
break;
680
}
681
}
682
683
if (viaTexture) {
684
OGLBlitToSurfaceViaTexture(oglc, &srcInfo, &pf, NULL,
685
JNI_TRUE, hint,
686
sx1, sy1, sx2, sy2,
687
dx1, dy1, dx2, dy2);
688
} else {
689
OGLBlitSwToSurface(oglc, &srcInfo, &pf,
690
sx1, sy1, sx2, sy2,
691
dx1, dy1, dx2, dy2);
692
}
693
}
694
695
j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
696
j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
697
}
698
SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
699
}
700
SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
701
}
702
703
/**
704
* This method makes vertical flip of the provided area of Surface and convert
705
* pixel's data from argbPre to argb format if requested.
706
*/
707
void flip(void *pDst, juint w, juint h, jint scanStride, jboolean convert) {
708
const size_t clippedStride = 4 * w;
709
void *tempRow = (h > 1 && !convert) ? malloc(clippedStride) : NULL;
710
juint i = 0;
711
juint step = 0;
712
// vertical flip and convert argbpre to argb if necessary
713
for (; i < h / 2; ++i) {
714
juint *r1 = PtrPixelsRow(pDst, i, scanStride);
715
juint *r2 = PtrPixelsRow(pDst, h - i - 1, scanStride);
716
if (tempRow) {
717
// fast path
718
memcpy(tempRow, r1, clippedStride);
719
memcpy(r1, r2, clippedStride);
720
memcpy(r2, tempRow, clippedStride);
721
} else {
722
// slow path
723
for (step = 0; step < w; ++step) {
724
juint tmp = r1[step];
725
if (convert) {
726
LoadIntArgbPreTo1IntArgb(r2, 0, step, r1[step]);
727
LoadIntArgbPreTo1IntArgb(&tmp, 0, 0, r2[step]);
728
} else {
729
r1[step] = r2[step];
730
r2[step] = tmp;
731
}
732
}
733
}
734
}
735
// convert the middle line if necessary
736
if (convert && h % 2) {
737
juint *r1 = PtrPixelsRow(pDst, i, scanStride);
738
for (step = 0; step < w; ++step) {
739
LoadIntArgbPreTo1IntArgb(r1, 0, step, r1[step]);
740
}
741
}
742
if (tempRow) {
743
free(tempRow);
744
}
745
}
746
747
/**
748
* Specialized blit method for copying a native OpenGL "Surface" (pbuffer,
749
* window, etc.) to a system memory ("Sw") surface.
750
*/
751
void
752
OGLBlitLoops_SurfaceToSwBlit(JNIEnv *env, OGLContext *oglc,
753
jlong pSrcOps, jlong pDstOps, jint dsttype,
754
jint srcx, jint srcy, jint dstx, jint dsty,
755
jint width, jint height)
756
{
757
OGLSDOps *srcOps = (OGLSDOps *)jlong_to_ptr(pSrcOps);
758
SurfaceDataOps *dstOps = (SurfaceDataOps *)jlong_to_ptr(pDstOps);
759
SurfaceDataRasInfo srcInfo, dstInfo;
760
OGLPixelFormat pf = PixelFormats[dsttype];
761
762
J2dTraceLn(J2D_TRACE_INFO, "OGLBlitLoops_SurfaceToSwBlit");
763
764
if (width <= 0 || height <= 0) {
765
J2dTraceLn(J2D_TRACE_WARNING,
766
"OGLBlitLoops_SurfaceToSwBlit: dimensions are non-positive");
767
return;
768
}
769
770
RETURN_IF_NULL(srcOps);
771
RETURN_IF_NULL(dstOps);
772
RETURN_IF_NULL(oglc);
773
RESET_PREVIOUS_OP();
774
775
srcInfo.bounds.x1 = srcx;
776
srcInfo.bounds.y1 = srcy;
777
srcInfo.bounds.x2 = srcx + width;
778
srcInfo.bounds.y2 = srcy + height;
779
dstInfo.bounds.x1 = dstx;
780
dstInfo.bounds.y1 = dsty;
781
dstInfo.bounds.x2 = dstx + width;
782
dstInfo.bounds.y2 = dsty + height;
783
784
if (dstOps->Lock(env, dstOps, &dstInfo, SD_LOCK_WRITE) != SD_SUCCESS) {
785
J2dTraceLn(J2D_TRACE_WARNING,
786
"OGLBlitLoops_SurfaceToSwBlit: could not acquire dst lock");
787
return;
788
}
789
790
SurfaceData_IntersectBoundsXYXY(&srcInfo.bounds,
791
0, 0, srcOps->width, srcOps->height);
792
SurfaceData_IntersectBlitBounds(&dstInfo.bounds, &srcInfo.bounds,
793
srcx - dstx, srcy - dsty);
794
795
if (srcInfo.bounds.x2 > srcInfo.bounds.x1 &&
796
srcInfo.bounds.y2 > srcInfo.bounds.y1)
797
{
798
dstOps->GetRasInfo(env, dstOps, &dstInfo);
799
if (dstInfo.rasBase) {
800
void *pDst = dstInfo.rasBase;
801
802
srcx = srcInfo.bounds.x1;
803
srcy = srcInfo.bounds.y1;
804
dstx = dstInfo.bounds.x1;
805
dsty = dstInfo.bounds.y1;
806
width = srcInfo.bounds.x2 - srcInfo.bounds.x1;
807
height = srcInfo.bounds.y2 - srcInfo.bounds.y1;
808
809
pDst = PtrAddBytes(pDst, dstx * dstInfo.pixelStride);
810
pDst = PtrPixelsRow(pDst, dsty, dstInfo.scanStride);
811
812
j2d_glPixelStorei(GL_PACK_ROW_LENGTH,
813
dstInfo.scanStride / dstInfo.pixelStride);
814
j2d_glPixelStorei(GL_PACK_ALIGNMENT, pf.alignment);
815
#ifdef MACOSX
816
if (srcOps->isOpaque) {
817
// For some reason Apple's OpenGL implementation will
818
// read back zero values from the alpha channel of an
819
// opaque surface when using glReadPixels(), so here we
820
// force the resulting pixels to be fully opaque.
821
j2d_glPixelTransferf(GL_ALPHA_BIAS, 1.0);
822
}
823
#endif
824
825
J2dTraceLn4(J2D_TRACE_VERBOSE, " sx=%d sy=%d w=%d h=%d",
826
srcx, srcy, width, height);
827
J2dTraceLn2(J2D_TRACE_VERBOSE, " dx=%d dy=%d",
828
dstx, dsty);
829
830
// this accounts for lower-left origin of the source region
831
srcx = srcOps->xOffset + srcx;
832
srcy = srcOps->yOffset + srcOps->height - srcy - height;
833
834
// Note that glReadPixels() is extremely slow!
835
// So we call it only once and flip the image using memcpy.
836
j2d_glReadPixels(srcx, srcy, width, height,
837
pf.format, pf.type, pDst);
838
// It was checked above that width and height are positive.
839
flip(pDst, (juint) width, (juint) height, dstInfo.scanStride,
840
!pf.isPremult && !srcOps->isOpaque);
841
#ifdef MACOSX
842
if (srcOps->isOpaque) {
843
j2d_glPixelTransferf(GL_ALPHA_BIAS, 0.0);
844
}
845
#endif
846
j2d_glPixelStorei(GL_PACK_ROW_LENGTH, 0);
847
j2d_glPixelStorei(GL_PACK_ALIGNMENT, 4);
848
}
849
SurfaceData_InvokeRelease(env, dstOps, &dstInfo);
850
}
851
SurfaceData_InvokeUnlock(env, dstOps, &dstInfo);
852
}
853
854
void
855
OGLBlitLoops_CopyArea(JNIEnv *env,
856
OGLContext *oglc, OGLSDOps *dstOps,
857
jint x, jint y, jint width, jint height,
858
jint dx, jint dy)
859
{
860
SurfaceDataBounds srcBounds, dstBounds;
861
862
J2dTraceLn(J2D_TRACE_INFO, "OGLBlitLoops_CopyArea");
863
864
RETURN_IF_NULL(oglc);
865
RETURN_IF_NULL(dstOps);
866
RESET_PREVIOUS_OP();
867
868
J2dTraceLn4(J2D_TRACE_VERBOSE, " x=%d y=%d w=%d h=%d",
869
x, y, width, height);
870
J2dTraceLn2(J2D_TRACE_VERBOSE, " dx=%d dy=%d",
871
dx, dy);
872
873
srcBounds.x1 = x;
874
srcBounds.y1 = y;
875
srcBounds.x2 = srcBounds.x1 + width;
876
srcBounds.y2 = srcBounds.y1 + height;
877
dstBounds.x1 = x + dx;
878
dstBounds.y1 = y + dy;
879
dstBounds.x2 = dstBounds.x1 + width;
880
dstBounds.y2 = dstBounds.y1 + height;
881
882
// 6430601: manually clip src/dst parameters to work around
883
// some bugs in Sun's and Apple's OpenGL implementations
884
// (it's a good idea to restrict the source parameters anyway, since
885
// passing out of range parameters to glCopyPixels() will result in
886
// an OpenGL error)
887
SurfaceData_IntersectBoundsXYXY(&srcBounds,
888
0, 0, dstOps->width, dstOps->height);
889
SurfaceData_IntersectBoundsXYXY(&dstBounds,
890
0, 0, dstOps->width, dstOps->height);
891
SurfaceData_IntersectBlitBounds(&dstBounds, &srcBounds, -dx, -dy);
892
893
if (dstBounds.x1 < dstBounds.x2 && dstBounds.y1 < dstBounds.y2) {
894
#ifdef MACOSX
895
if (dstOps->isOpaque) {
896
// For some reason Apple's OpenGL implementation will fail
897
// to render glCopyPixels() when the src/dst rectangles are
898
// overlapping and glColorMask() has disabled writes to the
899
// alpha channel. The workaround is to temporarily re-enable
900
// the alpha channel during the glCopyPixels() operation.
901
j2d_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
902
}
903
#endif
904
905
OGLBlitSurfaceToSurface(oglc, dstOps, dstOps,
906
srcBounds.x1, srcBounds.y1,
907
srcBounds.x2, srcBounds.y2,
908
dstBounds.x1, dstBounds.y1,
909
dstBounds.x2, dstBounds.y2);
910
#ifdef MACOSX
911
if (dstOps->isOpaque) {
912
j2d_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
913
}
914
#endif
915
}
916
}
917
918
#endif /* !HEADLESS */
919
920