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/OGLContext.c
38918 views
1
/*
2
* Copyright (c) 2004, 2013, 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 <stdlib.h>
29
#include <string.h>
30
31
#include "sun_java2d_SunGraphics2D.h"
32
33
#include "jlong.h"
34
#include "jni_util.h"
35
#include "OGLContext.h"
36
#include "OGLRenderQueue.h"
37
#include "OGLSurfaceData.h"
38
#include "GraphicsPrimitiveMgr.h"
39
#include "Region.h"
40
41
/**
42
* The following methods are implemented in the windowing system (i.e. GLX
43
* and WGL) source files.
44
*/
45
extern jboolean OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo);
46
extern OGLContext *OGLSD_MakeOGLContextCurrent(JNIEnv *env,
47
OGLSDOps *srcOps,
48
OGLSDOps *dstOps);
49
50
/**
51
* This table contains the standard blending rules (or Porter-Duff compositing
52
* factors) used in glBlendFunc(), indexed by the rule constants from the
53
* AlphaComposite class.
54
*/
55
OGLBlendRule StdBlendRules[] = {
56
{ GL_ZERO, GL_ZERO }, /* 0 - Nothing */
57
{ GL_ZERO, GL_ZERO }, /* 1 - RULE_Clear */
58
{ GL_ONE, GL_ZERO }, /* 2 - RULE_Src */
59
{ GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, /* 3 - RULE_SrcOver */
60
{ GL_ONE_MINUS_DST_ALPHA, GL_ONE }, /* 4 - RULE_DstOver */
61
{ GL_DST_ALPHA, GL_ZERO }, /* 5 - RULE_SrcIn */
62
{ GL_ZERO, GL_SRC_ALPHA }, /* 6 - RULE_DstIn */
63
{ GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, /* 7 - RULE_SrcOut */
64
{ GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, /* 8 - RULE_DstOut */
65
{ GL_ZERO, GL_ONE }, /* 9 - RULE_Dst */
66
{ GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /*10 - RULE_SrcAtop */
67
{ GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, /*11 - RULE_DstAtop */
68
{ GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /*12 - RULE_AlphaXor*/
69
};
70
71
/** Evaluates to "front" or "back", depending on the value of buf. */
72
#define OGLC_ACTIVE_BUFFER_NAME(buf) \
73
(buf == GL_FRONT || buf == GL_COLOR_ATTACHMENT0_EXT) ? "front" : "back"
74
75
/**
76
* Initializes the viewport and projection matrix, effectively positioning
77
* the origin at the top-left corner of the surface. This allows Java 2D
78
* coordinates to be passed directly to OpenGL, which is typically based on
79
* a bottom-right coordinate system. This method also sets the appropriate
80
* read and draw buffers.
81
*/
82
static void
83
OGLContext_SetViewport(OGLSDOps *srcOps, OGLSDOps *dstOps)
84
{
85
jint width = dstOps->width;
86
jint height = dstOps->height;
87
88
J2dTraceLn4(J2D_TRACE_INFO,
89
"OGLContext_SetViewport: w=%d h=%d read=%s draw=%s",
90
width, height,
91
OGLC_ACTIVE_BUFFER_NAME(srcOps->activeBuffer),
92
OGLC_ACTIVE_BUFFER_NAME(dstOps->activeBuffer));
93
94
// set the viewport and projection matrix
95
j2d_glViewport(dstOps->xOffset, dstOps->yOffset,
96
(GLsizei)width, (GLsizei)height);
97
j2d_glMatrixMode(GL_PROJECTION);
98
j2d_glLoadIdentity();
99
j2d_glOrtho(0.0, (GLdouble)width, (GLdouble)height, 0.0, -1.0, 1.0);
100
101
// set the active read and draw buffers
102
j2d_glReadBuffer(srcOps->activeBuffer);
103
j2d_glDrawBuffer(dstOps->activeBuffer);
104
105
// set the color mask to enable alpha channel only when necessary
106
j2d_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, (GLboolean)!dstOps->isOpaque);
107
}
108
109
/**
110
* Initializes the alpha channel of the current surface so that it contains
111
* fully opaque alpha values.
112
*/
113
static void
114
OGLContext_InitAlphaChannel()
115
{
116
GLboolean scissorEnabled;
117
118
J2dTraceLn(J2D_TRACE_INFO, "OGLContext_InitAlphaChannel");
119
120
// it is possible for the scissor test to be enabled at this point;
121
// if it is, disable it temporarily since it can affect the glClear() op
122
scissorEnabled = j2d_glIsEnabled(GL_SCISSOR_TEST);
123
if (scissorEnabled) {
124
j2d_glDisable(GL_SCISSOR_TEST);
125
}
126
127
// set the color mask so that we only affect the alpha channel
128
j2d_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
129
130
// clear the color buffer so that the alpha channel is fully opaque
131
j2d_glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
132
j2d_glClear(GL_COLOR_BUFFER_BIT);
133
134
// restore the color mask (as it was set in OGLContext_SetViewport())
135
j2d_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
136
137
// re-enable scissor test, only if it was enabled earlier
138
if (scissorEnabled) {
139
j2d_glEnable(GL_SCISSOR_TEST);
140
}
141
}
142
143
/**
144
* Fetches the OGLContext associated with the given destination surface,
145
* makes the context current for those surfaces, updates the destination
146
* viewport, and then returns a pointer to the OGLContext.
147
*/
148
OGLContext *
149
OGLContext_SetSurfaces(JNIEnv *env, jlong pSrc, jlong pDst)
150
{
151
OGLSDOps *srcOps = (OGLSDOps *)jlong_to_ptr(pSrc);
152
OGLSDOps *dstOps = (OGLSDOps *)jlong_to_ptr(pDst);
153
OGLContext *oglc = NULL;
154
155
J2dTraceLn(J2D_TRACE_INFO, "OGLContext_SetSurfaces");
156
157
if (srcOps == NULL || dstOps == NULL) {
158
J2dRlsTraceLn(J2D_TRACE_ERROR,
159
"OGLContext_SetSurfaces: ops are null");
160
return NULL;
161
}
162
163
J2dTraceLn2(J2D_TRACE_VERBOSE, " srctype=%d dsttype=%d",
164
srcOps->drawableType, dstOps->drawableType);
165
166
if (dstOps->drawableType == OGLSD_TEXTURE) {
167
J2dRlsTraceLn(J2D_TRACE_ERROR,
168
"OGLContext_SetSurfaces: texture cannot be used as destination");
169
return NULL;
170
}
171
172
if (dstOps->drawableType == OGLSD_UNDEFINED) {
173
// initialize the surface as an OGLSD_WINDOW
174
if (!OGLSD_InitOGLWindow(env, dstOps)) {
175
J2dRlsTraceLn(J2D_TRACE_ERROR,
176
"OGLContext_SetSurfaces: could not init OGL window");
177
return NULL;
178
}
179
}
180
181
// make the context current
182
oglc = OGLSD_MakeOGLContextCurrent(env, srcOps, dstOps);
183
if (oglc == NULL) {
184
J2dRlsTraceLn(J2D_TRACE_ERROR,
185
"OGLContext_SetSurfaces: could not make context current");
186
return NULL;
187
}
188
189
// update the viewport
190
OGLContext_SetViewport(srcOps, dstOps);
191
192
// perform additional one-time initialization, if necessary
193
if (dstOps->needsInit) {
194
if (dstOps->isOpaque) {
195
// in this case we are treating the destination as opaque, but
196
// to do so, first we need to ensure that the alpha channel
197
// is filled with fully opaque values (see 6319663)
198
OGLContext_InitAlphaChannel();
199
}
200
dstOps->needsInit = JNI_FALSE;
201
}
202
203
return oglc;
204
}
205
206
/**
207
* Resets the current clip state (disables both scissor and depth tests).
208
*/
209
void
210
OGLContext_ResetClip(OGLContext *oglc)
211
{
212
J2dTraceLn(J2D_TRACE_INFO, "OGLContext_ResetClip");
213
214
RETURN_IF_NULL(oglc);
215
CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
216
217
j2d_glDisable(GL_SCISSOR_TEST);
218
j2d_glDisable(GL_DEPTH_TEST);
219
}
220
221
/**
222
* Sets the OpenGL scissor bounds to the provided rectangular clip bounds.
223
*/
224
void
225
OGLContext_SetRectClip(OGLContext *oglc, OGLSDOps *dstOps,
226
jint x1, jint y1, jint x2, jint y2)
227
{
228
jint width = x2 - x1;
229
jint height = y2 - y1;
230
231
J2dTraceLn4(J2D_TRACE_INFO,
232
"OGLContext_SetRectClip: x=%d y=%d w=%d h=%d",
233
x1, y1, width, height);
234
235
RETURN_IF_NULL(dstOps);
236
RETURN_IF_NULL(oglc);
237
CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
238
239
if ((width < 0) || (height < 0)) {
240
// use an empty scissor rectangle when the region is empty
241
width = 0;
242
height = 0;
243
}
244
245
j2d_glDisable(GL_DEPTH_TEST);
246
j2d_glEnable(GL_SCISSOR_TEST);
247
248
// the scissor rectangle is specified using the lower-left
249
// origin of the clip region (in the framebuffer's coordinate
250
// space), so we must account for the x/y offsets of the
251
// destination surface
252
j2d_glScissor(dstOps->xOffset + x1,
253
dstOps->yOffset + dstOps->height - (y1 + height),
254
width, height);
255
}
256
257
/**
258
* Sets up a complex (shape) clip using the OpenGL depth buffer. This
259
* method prepares the depth buffer so that the clip Region spans can
260
* be "rendered" into it. The depth buffer is first cleared, then the
261
* depth func is setup so that when we render the clip spans,
262
* nothing is rendered into the color buffer, but for each pixel that would
263
* be rendered, a non-zero value is placed into that location in the depth
264
* buffer. With depth test enabled, pixels will only be rendered into the
265
* color buffer if the corresponding value at that (x,y) location in the
266
* depth buffer differs from the incoming depth value.
267
*/
268
void
269
OGLContext_BeginShapeClip(OGLContext *oglc)
270
{
271
J2dTraceLn(J2D_TRACE_INFO, "OGLContext_BeginShapeClip");
272
273
RETURN_IF_NULL(oglc);
274
RESET_PREVIOUS_OP();
275
276
j2d_glDisable(GL_SCISSOR_TEST);
277
278
// enable depth test and clear depth buffer so that depth values are at
279
// their maximum; also set the depth func to GL_ALWAYS so that the
280
// depth values of the clip spans are forced into the depth buffer
281
j2d_glEnable(GL_DEPTH_TEST);
282
j2d_glClearDepth(1.0);
283
j2d_glClear(GL_DEPTH_BUFFER_BIT);
284
j2d_glDepthFunc(GL_ALWAYS);
285
286
// disable writes into the color buffer while we set up the clip
287
j2d_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
288
289
// save current transform
290
j2d_glMatrixMode(GL_MODELVIEW);
291
j2d_glPushMatrix();
292
293
// use identity transform plus slight translation in the z-axis when
294
// setting the clip spans; this will push the clip spans (which would
295
// normally be at z=0) to the z=1 plane to give them some depth
296
j2d_glLoadIdentity();
297
j2d_glTranslatef(0.0f, 0.0f, 1.0f);
298
}
299
300
/**
301
* Finishes setting up the shape clip by resetting the depth func
302
* so that future rendering operations will once again be written into the
303
* color buffer (while respecting the clip set up in the depth buffer).
304
*/
305
void
306
OGLContext_EndShapeClip(OGLContext *oglc, OGLSDOps *dstOps)
307
{
308
J2dTraceLn(J2D_TRACE_INFO, "OGLContext_EndShapeClip");
309
310
RETURN_IF_NULL(dstOps);
311
RETURN_IF_NULL(oglc);
312
RESET_PREVIOUS_OP();
313
314
// restore transform
315
j2d_glPopMatrix();
316
317
// re-enable writes into the color buffer
318
j2d_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, (GLboolean)!dstOps->isOpaque);
319
320
// enable the depth test so that only fragments within the clip region
321
// (i.e. those fragments whose z-values are >= the values currently
322
// stored in the depth buffer) are rendered
323
j2d_glDepthFunc(GL_GEQUAL);
324
}
325
326
/**
327
* Initializes the OpenGL state responsible for applying extra alpha. This
328
* step is only necessary for any operation that uses glDrawPixels() or
329
* glCopyPixels() with a non-1.0f extra alpha value. Since the source is
330
* always premultiplied, we apply the extra alpha value to both alpha and
331
* color components using GL_*_SCALE.
332
*/
333
void
334
OGLContext_SetExtraAlpha(jfloat ea)
335
{
336
J2dTraceLn1(J2D_TRACE_INFO, "OGLContext_SetExtraAlpha: ea=%f", ea);
337
338
j2d_glPixelTransferf(GL_ALPHA_SCALE, ea);
339
j2d_glPixelTransferf(GL_RED_SCALE, ea);
340
j2d_glPixelTransferf(GL_GREEN_SCALE, ea);
341
j2d_glPixelTransferf(GL_BLUE_SCALE, ea);
342
}
343
344
/**
345
* Resets all OpenGL compositing state (disables blending and logic
346
* operations).
347
*/
348
void
349
OGLContext_ResetComposite(OGLContext *oglc)
350
{
351
J2dTraceLn(J2D_TRACE_INFO, "OGLContext_ResetComposite");
352
353
RETURN_IF_NULL(oglc);
354
CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
355
356
// disable blending and XOR mode
357
if (oglc->compState == sun_java2d_SunGraphics2D_COMP_ALPHA) {
358
j2d_glDisable(GL_BLEND);
359
} else if (oglc->compState == sun_java2d_SunGraphics2D_COMP_XOR) {
360
j2d_glDisable(GL_COLOR_LOGIC_OP);
361
j2d_glDisable(GL_ALPHA_TEST);
362
}
363
364
// set state to default values
365
oglc->compState = sun_java2d_SunGraphics2D_COMP_ISCOPY;
366
oglc->extraAlpha = 1.0f;
367
}
368
369
/**
370
* Initializes the OpenGL blending state. XOR mode is disabled and the
371
* appropriate blend functions are setup based on the AlphaComposite rule
372
* constant.
373
*/
374
void
375
OGLContext_SetAlphaComposite(OGLContext *oglc,
376
jint rule, jfloat extraAlpha, jint flags)
377
{
378
J2dTraceLn1(J2D_TRACE_INFO,
379
"OGLContext_SetAlphaComposite: flags=%d", flags);
380
381
RETURN_IF_NULL(oglc);
382
CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
383
384
// disable XOR mode
385
if (oglc->compState == sun_java2d_SunGraphics2D_COMP_XOR) {
386
j2d_glDisable(GL_COLOR_LOGIC_OP);
387
j2d_glDisable(GL_ALPHA_TEST);
388
}
389
390
// we can safely disable blending when:
391
// - comp is SrcNoEa or SrcOverNoEa, and
392
// - the source is opaque
393
// (turning off blending can have a large positive impact on
394
// performance)
395
if ((rule == RULE_Src || rule == RULE_SrcOver) &&
396
(extraAlpha == 1.0f) &&
397
(flags & OGLC_SRC_IS_OPAQUE))
398
{
399
J2dTraceLn1(J2D_TRACE_VERBOSE,
400
" disabling alpha comp: rule=%d ea=1.0 src=opq", rule);
401
j2d_glDisable(GL_BLEND);
402
} else {
403
J2dTraceLn2(J2D_TRACE_VERBOSE,
404
" enabling alpha comp: rule=%d ea=%f", rule, extraAlpha);
405
j2d_glEnable(GL_BLEND);
406
j2d_glBlendFunc(StdBlendRules[rule].src, StdBlendRules[rule].dst);
407
}
408
409
// update state
410
oglc->compState = sun_java2d_SunGraphics2D_COMP_ALPHA;
411
oglc->extraAlpha = extraAlpha;
412
}
413
414
/**
415
* Initializes the OpenGL logic op state to XOR mode. Blending is disabled
416
* before enabling logic op mode. The XOR pixel value will be applied
417
* later in the OGLContext_SetColor() method.
418
*/
419
void
420
OGLContext_SetXorComposite(OGLContext *oglc, jint xorPixel)
421
{
422
J2dTraceLn1(J2D_TRACE_INFO,
423
"OGLContext_SetXorComposite: xorPixel=%08x", xorPixel);
424
425
RETURN_IF_NULL(oglc);
426
CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
427
428
// disable blending mode
429
if (oglc->compState == sun_java2d_SunGraphics2D_COMP_ALPHA) {
430
j2d_glDisable(GL_BLEND);
431
}
432
433
// enable XOR mode
434
j2d_glEnable(GL_COLOR_LOGIC_OP);
435
j2d_glLogicOp(GL_XOR);
436
437
// set up the alpha test so that we discard transparent fragments (this
438
// is primarily useful for rendering text in XOR mode)
439
j2d_glEnable(GL_ALPHA_TEST);
440
j2d_glAlphaFunc(GL_NOTEQUAL, 0.0f);
441
442
// update state
443
oglc->compState = sun_java2d_SunGraphics2D_COMP_XOR;
444
oglc->xorPixel = xorPixel;
445
oglc->extraAlpha = 1.0f;
446
}
447
448
/**
449
* Resets the OpenGL transform state back to the identity matrix.
450
*/
451
void
452
OGLContext_ResetTransform(OGLContext *oglc)
453
{
454
J2dTraceLn(J2D_TRACE_INFO, "OGLContext_ResetTransform");
455
456
RETURN_IF_NULL(oglc);
457
CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
458
459
j2d_glMatrixMode(GL_MODELVIEW);
460
j2d_glLoadIdentity();
461
}
462
463
/**
464
* Initializes the OpenGL transform state by setting the modelview transform
465
* using the given matrix parameters.
466
*
467
* REMIND: it may be worthwhile to add serial id to AffineTransform, so we
468
* could do a quick check to see if the xform has changed since
469
* last time... a simple object compare won't suffice...
470
*/
471
void
472
OGLContext_SetTransform(OGLContext *oglc,
473
jdouble m00, jdouble m10,
474
jdouble m01, jdouble m11,
475
jdouble m02, jdouble m12)
476
{
477
J2dTraceLn(J2D_TRACE_INFO, "OGLContext_SetTransform");
478
479
RETURN_IF_NULL(oglc);
480
CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
481
482
if (oglc->xformMatrix == NULL) {
483
size_t arrsize = 16 * sizeof(GLdouble);
484
oglc->xformMatrix = (GLdouble *)malloc(arrsize);
485
memset(oglc->xformMatrix, 0, arrsize);
486
oglc->xformMatrix[10] = 1.0;
487
oglc->xformMatrix[15] = 1.0;
488
}
489
490
// copy values from AffineTransform object into native matrix array
491
oglc->xformMatrix[0] = m00;
492
oglc->xformMatrix[1] = m10;
493
oglc->xformMatrix[4] = m01;
494
oglc->xformMatrix[5] = m11;
495
oglc->xformMatrix[12] = m02;
496
oglc->xformMatrix[13] = m12;
497
498
J2dTraceLn3(J2D_TRACE_VERBOSE, " [%lf %lf %lf]",
499
oglc->xformMatrix[0], oglc->xformMatrix[4],
500
oglc->xformMatrix[12]);
501
J2dTraceLn3(J2D_TRACE_VERBOSE, " [%lf %lf %lf]",
502
oglc->xformMatrix[1], oglc->xformMatrix[5],
503
oglc->xformMatrix[13]);
504
505
j2d_glMatrixMode(GL_MODELVIEW);
506
j2d_glLoadMatrixd(oglc->xformMatrix);
507
}
508
509
/**
510
* Creates a 2D texture of the given format and dimensions and returns the
511
* texture object identifier. This method is typically used to create a
512
* temporary texture for intermediate work, such as in the
513
* OGLContext_InitBlitTileTexture() method below.
514
*/
515
GLuint
516
OGLContext_CreateBlitTexture(GLenum internalFormat, GLenum pixelFormat,
517
GLuint width, GLuint height)
518
{
519
GLuint texID;
520
GLint sp, sr, rl, align;
521
GLclampf priority = 1.0f;
522
523
J2dTraceLn(J2D_TRACE_INFO, "OGLContext_CreateBlitTexture");
524
525
j2d_glGenTextures(1, &texID);
526
j2d_glBindTexture(GL_TEXTURE_2D, texID);
527
j2d_glPrioritizeTextures(1, &texID, &priority);
528
j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
529
j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
530
OGLSD_RESET_TEXTURE_WRAP(GL_TEXTURE_2D);
531
532
// save pixel store parameters (since this method could be invoked after
533
// the caller has already set up its pixel store parameters)
534
j2d_glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &sp);
535
j2d_glGetIntegerv(GL_UNPACK_SKIP_ROWS, &sr);
536
j2d_glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rl);
537
j2d_glGetIntegerv(GL_UNPACK_ALIGNMENT, &align);
538
539
// set pixel store parameters to default values
540
j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
541
j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
542
j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
543
j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
544
545
j2d_glTexImage2D(GL_TEXTURE_2D, 0, internalFormat,
546
width, height, 0,
547
pixelFormat, GL_UNSIGNED_BYTE, NULL);
548
549
// restore pixel store parameters
550
j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, sp);
551
j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, sr);
552
j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, rl);
553
j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, align);
554
555
return texID;
556
}
557
558
/**
559
* Initializes a small texture tile for use with tiled blit operations (see
560
* OGLBlitLoops.c and OGLMaskBlit.c for usage examples). The texture ID for
561
* the tile is stored in the given OGLContext. The tile is initially filled
562
* with garbage values, but the tile is updated as needed (via
563
* glTexSubImage2D()) with real RGBA values used in tiled blit situations.
564
* The internal format for the texture is GL_RGBA8, which should be sufficient
565
* for storing system memory surfaces of any known format (see PixelFormats
566
* for a list of compatible surface formats).
567
*/
568
jboolean
569
OGLContext_InitBlitTileTexture(OGLContext *oglc)
570
{
571
J2dTraceLn(J2D_TRACE_INFO, "OGLContext_InitBlitTileTexture");
572
573
oglc->blitTextureID =
574
OGLContext_CreateBlitTexture(GL_RGBA8, GL_RGBA,
575
OGLC_BLIT_TILE_SIZE,
576
OGLC_BLIT_TILE_SIZE);
577
578
return JNI_TRUE;
579
}
580
581
/**
582
* Destroys the OpenGL resources associated with the given OGLContext.
583
* It is required that the native context associated with the OGLContext
584
* be made current prior to calling this method.
585
*/
586
void
587
OGLContext_DestroyContextResources(OGLContext *oglc)
588
{
589
J2dTraceLn(J2D_TRACE_INFO, "OGLContext_DestroyContextResources");
590
591
if (oglc->xformMatrix != NULL) {
592
free(oglc->xformMatrix);
593
}
594
595
if (oglc->blitTextureID != 0) {
596
j2d_glDeleteTextures(1, &oglc->blitTextureID);
597
}
598
}
599
600
/**
601
* Returns JNI_TRUE if the given extension name is available for the current
602
* GraphicsConfig; JNI_FALSE otherwise. An extension is considered available
603
* if its identifier string is found amongst the space-delimited GL_EXTENSIONS
604
* string.
605
*
606
* Adapted from the OpenGL Red Book, pg. 506.
607
*/
608
jboolean
609
OGLContext_IsExtensionAvailable(const char *extString, char *extName)
610
{
611
jboolean ret = JNI_FALSE;
612
char *p = (char *)extString;
613
char *end;
614
615
if (extString == NULL) {
616
J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsExtensionAvailable");
617
J2dRlsTraceLn(J2D_TRACE_ERROR,
618
"OGLContext_IsExtensionAvailable: extension string is null");
619
return JNI_FALSE;
620
}
621
622
end = p + strlen(p);
623
624
while (p < end) {
625
size_t n = strcspn(p, " ");
626
627
if ((strlen(extName) == n) && (strncmp(extName, p, n) == 0)) {
628
ret = JNI_TRUE;
629
break;
630
}
631
632
p += (n + 1);
633
}
634
635
J2dRlsTraceLn2(J2D_TRACE_INFO,
636
"OGLContext_IsExtensionAvailable: %s=%s",
637
extName, ret ? "true" : "false");
638
639
return ret;
640
}
641
642
/**
643
* Returns JNI_TRUE only if all of the following conditions are met:
644
* - the GL_EXT_framebuffer_object extension is available
645
* - FBO support has been enabled via the system property
646
* - we can successfully create an FBO with depth capabilities
647
*/
648
static jboolean
649
OGLContext_IsFBObjectExtensionAvailable(JNIEnv *env,
650
const char *extString)
651
{
652
jboolean isFBObjectEnabled = JNI_FALSE;
653
GLuint fbobjectID, textureID, depthID;
654
jint width = 1, height = 1;
655
656
J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsFBObjectExtensionAvailable");
657
658
// first see if the fbobject extension is available
659
if (!OGLContext_IsExtensionAvailable(extString,
660
"GL_EXT_framebuffer_object"))
661
{
662
return JNI_FALSE;
663
}
664
665
// next see if the depth texture extension is available
666
if (!OGLContext_IsExtensionAvailable(extString,
667
"GL_ARB_depth_texture"))
668
{
669
return JNI_FALSE;
670
}
671
672
// next see if the fbobject system property has been enabled
673
isFBObjectEnabled =
674
JNU_GetStaticFieldByName(env, NULL,
675
"sun/java2d/opengl/OGLSurfaceData",
676
"isFBObjectEnabled", "Z").z;
677
if (!isFBObjectEnabled) {
678
J2dRlsTraceLn(J2D_TRACE_INFO,
679
"OGLContext_IsFBObjectExtensionAvailable: disabled via flag");
680
return JNI_FALSE;
681
}
682
683
// finally, create a dummy fbobject with depth capabilities to see
684
// if this configuration is supported by the drivers/hardware
685
// (first we initialize a color texture object that will be used to
686
// construct the dummy fbobject)
687
j2d_glGenTextures(1, &textureID);
688
j2d_glBindTexture(GL_TEXTURE_2D, textureID);
689
j2d_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
690
width, height, 0,
691
GL_RGB, GL_UNSIGNED_BYTE, NULL);
692
j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
693
j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
694
695
// initialize framebuffer object using color texture created above
696
if (!OGLSD_InitFBObject(&fbobjectID, &depthID,
697
textureID, GL_TEXTURE_2D,
698
width, height))
699
{
700
J2dRlsTraceLn(J2D_TRACE_INFO,
701
"OGLContext_IsFBObjectExtensionAvailable: fbobject unsupported");
702
j2d_glDeleteTextures(1, &textureID);
703
return JNI_FALSE;
704
}
705
706
// delete the temporary resources
707
j2d_glDeleteTextures(1, &textureID);
708
j2d_glDeleteRenderbuffersEXT(1, &depthID);
709
j2d_glDeleteFramebuffersEXT(1, &fbobjectID);
710
711
J2dRlsTraceLn(J2D_TRACE_INFO,
712
"OGLContext_IsFBObjectExtensionAvailable: fbobject supported");
713
714
return JNI_TRUE;
715
}
716
717
/**
718
* Returns JNI_TRUE only if all of the following conditions are met:
719
* - the GL_ARB_fragment_shader extension is available
720
* - the LCD text shader codepath has been enabled via the system property
721
* - the hardware supports the minimum number of texture units
722
*/
723
static jboolean
724
OGLContext_IsLCDShaderSupportAvailable(JNIEnv *env,
725
jboolean fragShaderAvailable)
726
{
727
jboolean isLCDShaderEnabled = JNI_FALSE;
728
GLint maxTexUnits;
729
730
J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsLCDShaderSupportAvailable");
731
732
// first see if the fragment shader extension is available
733
if (!fragShaderAvailable) {
734
return JNI_FALSE;
735
}
736
737
// next see if the lcdshader system property has been enabled
738
isLCDShaderEnabled =
739
JNU_GetStaticFieldByName(env, NULL,
740
"sun/java2d/opengl/OGLSurfaceData",
741
"isLCDShaderEnabled", "Z").z;
742
if (!isLCDShaderEnabled) {
743
J2dRlsTraceLn(J2D_TRACE_INFO,
744
"OGLContext_IsLCDShaderSupportAvailable: disabled via flag");
745
return JNI_FALSE;
746
}
747
748
// finally, check to see if the hardware supports the required number
749
// of texture units
750
j2d_glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &maxTexUnits);
751
if (maxTexUnits < 2) {
752
J2dRlsTraceLn1(J2D_TRACE_INFO,
753
"OGLContext_IsLCDShaderSupportAvailable: not enough tex units (%d)",
754
maxTexUnits);
755
}
756
757
J2dRlsTraceLn(J2D_TRACE_INFO,
758
"OGLContext_IsLCDShaderSupportAvailable: LCD text shader supported");
759
760
return JNI_TRUE;
761
}
762
763
/**
764
* Returns JNI_TRUE only if all of the following conditions are met:
765
* - the GL_ARB_fragment_shader extension is available
766
* - the BufferedImageOp shader codepath has been enabled via the
767
* system property
768
*/
769
static jboolean
770
OGLContext_IsBIOpShaderSupportAvailable(JNIEnv *env,
771
jboolean fragShaderAvailable)
772
{
773
jboolean isBIOpShaderEnabled = JNI_FALSE;
774
775
J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsBIOpShaderSupportAvailable");
776
777
// first see if the fragment shader extension is available
778
if (!fragShaderAvailable) {
779
return JNI_FALSE;
780
}
781
782
// next see if the biopshader system property has been enabled
783
isBIOpShaderEnabled =
784
JNU_GetStaticFieldByName(env, NULL,
785
"sun/java2d/opengl/OGLSurfaceData",
786
"isBIOpShaderEnabled", "Z").z;
787
if (!isBIOpShaderEnabled) {
788
J2dRlsTraceLn(J2D_TRACE_INFO,
789
"OGLContext_IsBIOpShaderSupportAvailable: disabled via flag");
790
return JNI_FALSE;
791
}
792
793
/*
794
* Note: In theory we should probably do some other checks here, like
795
* linking a sample shader to see if the hardware truly supports our
796
* shader programs. However, our current BufferedImageOp shaders were
797
* designed to support first-generation shader-level hardware, so the
798
* assumption is that if our shaders work on those GPUs, then they'll
799
* work on newer ones as well. Also, linking a fragment program can
800
* cost valuable CPU cycles, which is another reason to avoid these
801
* checks at startup.
802
*/
803
804
J2dRlsTraceLn(J2D_TRACE_INFO,
805
"OGLContext_IsBIOpShaderSupportAvailable: BufferedImageOp shader supported");
806
807
return JNI_TRUE;
808
}
809
810
/**
811
* Returns JNI_TRUE only if all of the following conditions are met:
812
* - the GL_ARB_fragment_shader extension is available
813
* - the Linear/RadialGradientPaint shader codepath has been enabled via the
814
* system property
815
*/
816
static jboolean
817
OGLContext_IsGradShaderSupportAvailable(JNIEnv *env,
818
jboolean fragShaderAvailable)
819
{
820
jboolean isGradShaderEnabled = JNI_FALSE;
821
822
J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsGradShaderSupportAvailable");
823
824
// first see if the fragment shader extension is available
825
if (!fragShaderAvailable) {
826
return JNI_FALSE;
827
}
828
829
// next see if the gradshader system property has been enabled
830
isGradShaderEnabled =
831
JNU_GetStaticFieldByName(env, NULL,
832
"sun/java2d/opengl/OGLSurfaceData",
833
"isGradShaderEnabled", "Z").z;
834
if (!isGradShaderEnabled) {
835
J2dRlsTraceLn(J2D_TRACE_INFO,
836
"OGLContext_IsGradShaderSupportAvailable: disabled via flag");
837
return JNI_FALSE;
838
}
839
840
J2dRlsTraceLn(J2D_TRACE_INFO,
841
"OGLContext_IsGradShaderSupportAvailable: Linear/RadialGradientPaint shader supported");
842
843
return JNI_TRUE;
844
}
845
846
/**
847
* Checks for the presence of the optional extensions used by
848
* the Java 2D OpenGL pipeline. The given caps bitfield is updated
849
* to reflect the availability of these extensions.
850
*/
851
void
852
OGLContext_GetExtensionInfo(JNIEnv *env, jint *caps)
853
{
854
jint vcap = OGLC_VENDOR_OTHER;
855
const char *vendor = (char *)j2d_glGetString(GL_VENDOR);
856
const char *e = (char *)j2d_glGetString(GL_EXTENSIONS);
857
jboolean fragShaderAvail =
858
OGLContext_IsExtensionAvailable(e, "GL_ARB_fragment_shader");
859
860
J2dTraceLn(J2D_TRACE_INFO, "OGLContext_GetExtensionInfo");
861
862
*caps |= CAPS_TEXNONSQUARE;
863
if (OGLContext_IsExtensionAvailable(e, "GL_ARB_multitexture")) {
864
*caps |= CAPS_MULTITEXTURE;
865
}
866
if (OGLContext_IsExtensionAvailable(e, "GL_ARB_texture_non_power_of_two")){
867
*caps |= CAPS_TEXNONPOW2;
868
}
869
// 6656574: Use of the GL_ARB_texture_rectangle extension by Java 2D
870
// complicates any third-party libraries that try to interact with
871
// the OGL pipeline (and we've run into driver bugs in the past related
872
// to this extension), so for now we will disable its use by default (unless
873
// forced). We will still make use of the GL_ARB_texture_non_power_of_two
874
// extension when available, which is the better choice going forward
875
// anyway.
876
if (OGLContext_IsExtensionAvailable(e, "GL_ARB_texture_rectangle") &&
877
getenv("J2D_OGL_TEXRECT") != NULL)
878
{
879
*caps |= CAPS_EXT_TEXRECT;
880
}
881
if (OGLContext_IsFBObjectExtensionAvailable(env, e)) {
882
*caps |= CAPS_EXT_FBOBJECT;
883
}
884
if (OGLContext_IsLCDShaderSupportAvailable(env, fragShaderAvail)) {
885
*caps |= CAPS_EXT_LCD_SHADER | CAPS_PS20;
886
}
887
if (OGLContext_IsBIOpShaderSupportAvailable(env, fragShaderAvail)) {
888
*caps |= CAPS_EXT_BIOP_SHADER | CAPS_PS20;
889
}
890
if (OGLContext_IsGradShaderSupportAvailable(env, fragShaderAvail)) {
891
*caps |= CAPS_EXT_GRAD_SHADER | CAPS_PS20;
892
}
893
if (OGLContext_IsExtensionAvailable(e, "GL_NV_fragment_program")) {
894
// this is an Nvidia board, at least PS 2.0, but we can't
895
// use the "max instructions" heuristic since GeForce FX
896
// boards report 1024 even though they're only PS 2.0,
897
// so we'll check the following, which does imply PS 3.0
898
if (OGLContext_IsExtensionAvailable(e, "GL_NV_fragment_program2")) {
899
*caps |= CAPS_PS30;
900
}
901
} else {
902
// for all other boards, we look at the "max instructions"
903
// count reported by the GL_ARB_fragment_program extension
904
// as a heuristic for detecting PS 3.0 compatible hardware
905
if (OGLContext_IsExtensionAvailable(e, "GL_ARB_fragment_program")) {
906
GLint instr;
907
j2d_glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
908
GL_MAX_PROGRAM_INSTRUCTIONS_ARB, &instr);
909
if (instr > 512) {
910
*caps |= CAPS_PS30;
911
}
912
}
913
}
914
if (OGLContext_IsExtensionAvailable(e, "GL_NV_texture_barrier")) {
915
*caps |= CAPS_EXT_TEXBARRIER;
916
}
917
918
// stuff vendor descriptor in the upper bits of the caps
919
if (vendor != NULL) {
920
if (strncmp(vendor, "ATI", 3) == 0) {
921
vcap = OGLC_VENDOR_ATI;
922
} else if (strncmp(vendor, "NVIDIA", 6) == 0) {
923
vcap = OGLC_VENDOR_NVIDIA;
924
} else if (strncmp(vendor, "Intel", 5) == 0) {
925
vcap = OGLC_VENDOR_INTEL;
926
}
927
// REMIND: new in 7 - check if needs fixing
928
*caps |= ((vcap & OGLC_VCAP_MASK) << OGLC_VCAP_OFFSET);
929
}
930
931
}
932
933
/**
934
* Returns JNI_TRUE if the given GL_VERSION string meets the minimum
935
* requirements (>= 1.2); JNI_FALSE otherwise.
936
*/
937
jboolean
938
OGLContext_IsVersionSupported(const unsigned char *versionstr)
939
{
940
J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsVersionSupported");
941
942
if (versionstr == NULL) {
943
J2dRlsTraceLn(J2D_TRACE_ERROR,
944
"OGLContext_IsVersionSupported: version string is null");
945
return JNI_FALSE;
946
}
947
948
// note that this check allows for OpenGL 2.x
949
return ((versionstr[0] == '1' && versionstr[2] >= '2') ||
950
(versionstr[0] >= '2'));
951
}
952
953
/**
954
* Compiles and links the given fragment shader program. If
955
* successful, this function returns a handle to the newly created shader
956
* program; otherwise returns 0.
957
*/
958
GLhandleARB
959
OGLContext_CreateFragmentProgram(const char *fragmentShaderSource)
960
{
961
GLhandleARB fragmentShader, fragmentProgram;
962
GLint success;
963
int infoLogLength = 0;
964
965
J2dTraceLn(J2D_TRACE_INFO, "OGLContext_CreateFragmentProgram");
966
967
// create the shader object and compile the shader source code
968
fragmentShader = j2d_glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
969
j2d_glShaderSourceARB(fragmentShader, 1, &fragmentShaderSource, NULL);
970
j2d_glCompileShaderARB(fragmentShader);
971
j2d_glGetObjectParameterivARB(fragmentShader,
972
GL_OBJECT_COMPILE_STATUS_ARB,
973
&success);
974
975
// print the compiler messages, if necessary
976
j2d_glGetObjectParameterivARB(fragmentShader,
977
GL_OBJECT_INFO_LOG_LENGTH_ARB,
978
&infoLogLength);
979
if (infoLogLength > 1) {
980
char infoLog[1024];
981
j2d_glGetInfoLogARB(fragmentShader, 1024, NULL, infoLog);
982
J2dRlsTraceLn2(J2D_TRACE_WARNING,
983
"OGLContext_CreateFragmentProgram: compiler msg (%d):\n%s",
984
infoLogLength, infoLog);
985
}
986
987
if (!success) {
988
J2dRlsTraceLn(J2D_TRACE_ERROR,
989
"OGLContext_CreateFragmentProgram: error compiling shader");
990
j2d_glDeleteObjectARB(fragmentShader);
991
return 0;
992
}
993
994
// create the program object and attach it to the shader
995
fragmentProgram = j2d_glCreateProgramObjectARB();
996
j2d_glAttachObjectARB(fragmentProgram, fragmentShader);
997
998
// it is now safe to delete the shader object
999
j2d_glDeleteObjectARB(fragmentShader);
1000
1001
// link the program
1002
j2d_glLinkProgramARB(fragmentProgram);
1003
j2d_glGetObjectParameterivARB(fragmentProgram,
1004
GL_OBJECT_LINK_STATUS_ARB,
1005
&success);
1006
1007
// print the linker messages, if necessary
1008
j2d_glGetObjectParameterivARB(fragmentProgram,
1009
GL_OBJECT_INFO_LOG_LENGTH_ARB,
1010
&infoLogLength);
1011
if (infoLogLength > 1) {
1012
char infoLog[1024];
1013
j2d_glGetInfoLogARB(fragmentProgram, 1024, NULL, infoLog);
1014
J2dRlsTraceLn2(J2D_TRACE_WARNING,
1015
"OGLContext_CreateFragmentProgram: linker msg (%d):\n%s",
1016
infoLogLength, infoLog);
1017
}
1018
1019
if (!success) {
1020
J2dRlsTraceLn(J2D_TRACE_ERROR,
1021
"OGLContext_CreateFragmentProgram: error linking shader");
1022
j2d_glDeleteObjectARB(fragmentProgram);
1023
return 0;
1024
}
1025
1026
return fragmentProgram;
1027
}
1028
1029
/*
1030
* Class: sun_java2d_opengl_OGLContext
1031
* Method: getOGLIdString
1032
* Signature: ()Ljava/lang/String;
1033
*/
1034
JNIEXPORT jstring JNICALL Java_sun_java2d_opengl_OGLContext_getOGLIdString
1035
(JNIEnv *env, jclass oglcc)
1036
{
1037
char *vendor, *renderer, *version;
1038
char *pAdapterId;
1039
jobject ret = NULL;
1040
int len;
1041
1042
J2dTraceLn(J2D_TRACE_INFO, "OGLContext_getOGLIdString");
1043
1044
vendor = (char*)j2d_glGetString(GL_VENDOR);
1045
if (vendor == NULL) {
1046
vendor = "Unknown Vendor";
1047
}
1048
renderer = (char*)j2d_glGetString(GL_RENDERER);
1049
if (renderer == NULL) {
1050
renderer = "Unknown Renderer";
1051
}
1052
version = (char*)j2d_glGetString(GL_VERSION);
1053
if (version == NULL) {
1054
version = "unknown version";
1055
}
1056
1057
// 'vendor renderer (version)0'
1058
len = strlen(vendor) + 1 + strlen(renderer) + 1 + 1+strlen(version)+1 + 1;
1059
pAdapterId = malloc(len);
1060
if (pAdapterId != NULL) {
1061
1062
jio_snprintf(pAdapterId, len, "%s %s (%s)", vendor, renderer, version);
1063
1064
J2dTraceLn1(J2D_TRACE_VERBOSE, " id=%s", pAdapterId);
1065
1066
ret = JNU_NewStringPlatform(env, pAdapterId);
1067
1068
free(pAdapterId);
1069
}
1070
1071
return ret;
1072
}
1073
1074
#endif /* !HEADLESS */
1075
1076