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