mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-08 10:29:40 +01:00
752 lines
27 KiB
C
752 lines
27 KiB
C
/*
|
|
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation. Oracle designates this
|
|
* particular file as subject to the "Classpath" exception as provided
|
|
* by Oracle in the LICENSE file that accompanied this code.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
#ifndef HEADLESS
|
|
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
|
|
#include "sun_java2d_opengl_OGLSurfaceData.h"
|
|
|
|
#include "jlong.h"
|
|
#include "jni_util.h"
|
|
#include "OGLSurfaceData.h"
|
|
|
|
/**
|
|
* The following methods are implemented in the windowing system (i.e. GLX
|
|
* and WGL) source files.
|
|
*/
|
|
extern jboolean OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo);
|
|
extern void OGLSD_DestroyOGLSurface(JNIEnv *env, OGLSDOps *oglsdo);
|
|
|
|
void OGLSD_SetNativeDimensions(JNIEnv *env, OGLSDOps *oglsdo, jint w, jint h);
|
|
extern void OGLBlitRasterToSurface(OGLSDOps *dstOps, jlong pRaster, jint width, jint height,
|
|
OGLPixelFormat *pf,
|
|
jint sx1, jint sy1, jint sx2, jint sy2,
|
|
jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2);
|
|
|
|
/**
|
|
* This table contains the "pixel formats" for all system memory surfaces
|
|
* that OpenGL is capable of handling, indexed by the "PF_" constants defined
|
|
* in OGLSurfaceData.java. These pixel formats contain information that is
|
|
* passed to OpenGL when copying from a system memory ("Sw") surface to
|
|
* an OpenGL "Surface" (via glDrawPixels()) or "Texture" (via glTexImage2D()).
|
|
*/
|
|
OGLPixelFormat PixelFormats[] = {
|
|
{ GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
|
|
4, 1, 0, }, /* 0 - IntArgb */
|
|
{ GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
|
|
4, 1, 1, }, /* 1 - IntArgbPre */
|
|
{ GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
|
|
4, 0, 1, }, /* 2 - IntRgb */
|
|
{ GL_RGBA, GL_UNSIGNED_INT_8_8_8_8,
|
|
4, 0, 1, }, /* 3 - IntRgbx */
|
|
{ GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV,
|
|
4, 0, 1, }, /* 4 - IntBgr */
|
|
{ GL_BGRA, GL_UNSIGNED_INT_8_8_8_8,
|
|
4, 0, 1, }, /* 5 - IntBgrx */
|
|
{ GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
|
|
2, 0, 1, }, /* 6 - Ushort565Rgb */
|
|
{ GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV,
|
|
2, 0, 1, }, /* 7 - Ushort555Rgb */
|
|
{ GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1,
|
|
2, 0, 1, }, /* 8 - Ushort555Rgbx*/
|
|
{ GL_LUMINANCE, GL_UNSIGNED_BYTE,
|
|
1, 0, 1, }, /* 9 - ByteGray */
|
|
{ GL_LUMINANCE, GL_UNSIGNED_SHORT,
|
|
2, 0, 1, }, /*10 - UshortGray */
|
|
{ GL_BGR, GL_UNSIGNED_BYTE,
|
|
1, 0, 1, }, /*11 - ThreeByteBgr */};
|
|
|
|
/**
|
|
* Given a starting value and a maximum limit, returns the first power-of-two
|
|
* greater than the starting value. If the resulting value is greater than
|
|
* the maximum limit, zero is returned.
|
|
*/
|
|
jint
|
|
OGLSD_NextPowerOfTwo(jint val, jint max)
|
|
{
|
|
jint i;
|
|
|
|
if (val > max) {
|
|
return 0;
|
|
}
|
|
|
|
for (i = 1; i < val; i *= 2);
|
|
|
|
return i;
|
|
}
|
|
|
|
/**
|
|
* Returns true if both given dimensions are a power of two.
|
|
*/
|
|
static jboolean
|
|
OGLSD_IsPowerOfTwo(jint width, jint height)
|
|
{
|
|
return (((width & (width-1)) | (height & (height-1))) == 0);
|
|
}
|
|
|
|
/**
|
|
* Initializes an OpenGL texture object.
|
|
*
|
|
* If the isOpaque parameter is JNI_FALSE, then the texture will have a
|
|
* full alpha channel; otherwise, the texture will be opaque (this can
|
|
* help save VRAM when translucency is not needed).
|
|
*
|
|
* If the GL_ARB_texture_non_power_of_two extension is present (texNonPow2
|
|
* is JNI_TRUE), the actual texture is allowed to have non-power-of-two
|
|
* dimensions, and therefore width==textureWidth and height==textureHeight.
|
|
*
|
|
* Failing that, if the GL_ARB_texture_rectangle extension is present
|
|
* (texRect is JNI_TRUE), the actual texture is allowed to have
|
|
* non-power-of-two dimensions, except that instead of using the usual
|
|
* GL_TEXTURE_2D target, we need to use the GL_TEXTURE_RECTANGLE_ARB target.
|
|
* Note that the GL_REPEAT wrapping mode is not allowed with this target,
|
|
* so if that mode is needed (e.g. as is the case in the TexturePaint code)
|
|
* one should pass JNI_FALSE to avoid using this extension. Also note that
|
|
* when the texture target is GL_TEXTURE_RECTANGLE_ARB, texture coordinates
|
|
* must be specified in the range [0,width] and [0,height] rather than
|
|
* [0,1] as is the case with the usual GL_TEXTURE_2D target (so take care)!
|
|
*
|
|
* Otherwise, the actual texture must have power-of-two dimensions, and
|
|
* therefore the textureWidth and textureHeight will be the next
|
|
* power-of-two greater than (or equal to) the requested width and height.
|
|
*/
|
|
static jboolean
|
|
OGLSD_InitTextureObject(OGLSDOps *oglsdo,
|
|
jboolean isOpaque,
|
|
jboolean texNonPow2, jboolean texRect,
|
|
jint width, jint height)
|
|
{
|
|
GLenum texTarget, texProxyTarget;
|
|
GLint format = GL_RGBA;
|
|
GLint size = GL_UNSIGNED_INT_8_8_8_8;
|
|
GLuint texID;
|
|
GLsizei texWidth, texHeight, realWidth, realHeight;
|
|
GLint texMax;
|
|
|
|
J2dTraceLn4(J2D_TRACE_INFO,
|
|
"OGLSD_InitTextureObject: w=%d h=%d opq=%d nonpow2=%d",
|
|
width, height, isOpaque, texNonPow2);
|
|
|
|
if (oglsdo == NULL) {
|
|
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
|
"OGLSD_InitTextureObject: ops are null");
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
if (texNonPow2) {
|
|
// use non-pow2 dimensions with GL_TEXTURE_2D target
|
|
j2d_glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texMax);
|
|
texWidth = (width <= texMax) ? width : 0;
|
|
texHeight = (height <= texMax) ? height : 0;
|
|
texTarget = GL_TEXTURE_2D;
|
|
texProxyTarget = GL_PROXY_TEXTURE_2D;
|
|
} else if (texRect) {
|
|
// use non-pow2 dimensions with GL_TEXTURE_RECTANGLE_ARB target
|
|
j2d_glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &texMax);
|
|
texWidth = (width <= texMax) ? width : 0;
|
|
texHeight = (height <= texMax) ? height : 0;
|
|
texTarget = GL_TEXTURE_RECTANGLE_ARB;
|
|
texProxyTarget = GL_PROXY_TEXTURE_RECTANGLE_ARB;
|
|
} else {
|
|
// find the appropriate power-of-two dimensions
|
|
j2d_glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texMax);
|
|
texWidth = OGLSD_NextPowerOfTwo(width, texMax);
|
|
texHeight = OGLSD_NextPowerOfTwo(height, texMax);
|
|
texTarget = GL_TEXTURE_2D;
|
|
texProxyTarget = GL_PROXY_TEXTURE_2D;
|
|
}
|
|
|
|
J2dTraceLn3(J2D_TRACE_VERBOSE,
|
|
" desired texture dimensions: w=%d h=%d max=%d",
|
|
texWidth, texHeight, texMax);
|
|
|
|
// if either dimension is 0, we cannot allocate a texture with the
|
|
// requested dimensions
|
|
if ((texWidth == 0) || (texHeight == 0)) {
|
|
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
|
"OGLSD_InitTextureObject: texture dimensions too large");
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
// now use a proxy to determine whether we can create a texture with
|
|
// the calculated power-of-two dimensions and the given internal format
|
|
j2d_glTexImage2D(texProxyTarget, 0, format,
|
|
texWidth, texHeight, 0,
|
|
format, size, NULL);
|
|
j2d_glGetTexLevelParameteriv(texProxyTarget, 0,
|
|
GL_TEXTURE_WIDTH, &realWidth);
|
|
j2d_glGetTexLevelParameteriv(texProxyTarget, 0,
|
|
GL_TEXTURE_HEIGHT, &realHeight);
|
|
|
|
// if the requested dimensions and proxy dimensions don't match,
|
|
// we shouldn't attempt to create the texture
|
|
if ((realWidth != texWidth) || (realHeight != texHeight)) {
|
|
J2dRlsTraceLn2(J2D_TRACE_ERROR,
|
|
"OGLSD_InitTextureObject: actual (w=%d h=%d) != requested",
|
|
realWidth, realHeight);
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
// initialize the texture with some dummy data (this allows us to create
|
|
// a texture object once with 2^n dimensions, and then use
|
|
// glTexSubImage2D() to provide further updates)
|
|
j2d_glGenTextures(1, &texID);
|
|
j2d_glBindTexture(texTarget, texID);
|
|
j2d_glTexImage2D(texTarget, 0, format,
|
|
texWidth, texHeight, 0,
|
|
format, size, NULL);
|
|
|
|
oglsdo->isOpaque = isOpaque;
|
|
oglsdo->xOffset = 0;
|
|
oglsdo->yOffset = 0;
|
|
oglsdo->width = width;
|
|
oglsdo->height = height;
|
|
oglsdo->textureID = texID;
|
|
oglsdo->textureWidth = texWidth;
|
|
oglsdo->textureHeight = texHeight;
|
|
oglsdo->textureTarget = texTarget;
|
|
OGLSD_INIT_TEXTURE_FILTER(oglsdo, GL_NEAREST);
|
|
OGLSD_RESET_TEXTURE_WRAP(texTarget);
|
|
|
|
J2dTraceLn3(J2D_TRACE_VERBOSE, " created texture: w=%d h=%d id=%d",
|
|
width, height, texID);
|
|
|
|
return JNI_TRUE;
|
|
}
|
|
|
|
/**
|
|
* Initializes an OpenGL texture, using the given width and height as
|
|
* a guide. See OGLSD_InitTextureObject() for more information.
|
|
*/
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_sun_java2d_opengl_OGLSurfaceData_initTexture
|
|
(JNIEnv *env, jobject oglsd,
|
|
jlong pData, jboolean isOpaque,
|
|
jboolean texNonPow2, jboolean texRect,
|
|
jint width, jint height)
|
|
{
|
|
OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData);
|
|
|
|
J2dTraceLn2(J2D_TRACE_INFO, "OGLSurfaceData_initTexture: w=%d h=%d",
|
|
width, height);
|
|
|
|
if (oglsdo == NULL) {
|
|
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
|
"OGLSurfaceData_initTexture: ops are null");
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
/*
|
|
* We only use the GL_ARB_texture_rectangle extension if it is available
|
|
* and the requested bounds are not pow2 (it is probably faster to use
|
|
* GL_TEXTURE_2D for pow2 textures, and besides, our TexturePaint
|
|
* code relies on GL_REPEAT, which is not allowed for
|
|
* GL_TEXTURE_RECTANGLE_ARB targets).
|
|
*/
|
|
texRect = texRect && !OGLSD_IsPowerOfTwo(width, height);
|
|
|
|
if (!OGLSD_InitTextureObject(oglsdo, isOpaque, texNonPow2, texRect,
|
|
width, height))
|
|
{
|
|
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
|
"OGLSurfaceData_initTexture: could not init texture object");
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
OGLSD_SetNativeDimensions(env, oglsdo,
|
|
oglsdo->textureWidth, oglsdo->textureHeight);
|
|
|
|
oglsdo->drawableType = OGLSD_TEXTURE;
|
|
// other fields (e.g. width, height) are set in OGLSD_InitTextureObject()
|
|
|
|
return JNI_TRUE;
|
|
}
|
|
|
|
/**
|
|
* Initializes a framebuffer object based on the given textureID and its
|
|
* width/height. This method will iterate through all possible depth formats
|
|
* to find one that is supported by the drivers/hardware. (Since our use of
|
|
* the depth buffer is fairly simplistic, we hope to find a depth format that
|
|
* uses as little VRAM as possible.) If an appropriate depth buffer is found
|
|
* and all attachments are successful (i.e. the framebuffer object is
|
|
* "complete"), then this method will return JNI_TRUE and will initialize
|
|
* the values of fbobjectID and depthID using the IDs created by this method.
|
|
* Otherwise, this method returns JNI_FALSE. Note that the caller is only
|
|
* responsible for deleting the allocated fbobject and depth renderbuffer
|
|
* resources if this method returned JNI_TRUE.
|
|
*/
|
|
jboolean
|
|
OGLSD_InitFBObject(GLuint *fbobjectID, GLuint *depthID,
|
|
GLuint textureID, GLenum textureTarget,
|
|
jint textureWidth, jint textureHeight)
|
|
{
|
|
GLenum depthFormats[] = {
|
|
GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT32
|
|
};
|
|
GLuint fboTmpID, depthTmpID;
|
|
jboolean foundDepth = JNI_FALSE;
|
|
int i;
|
|
|
|
J2dTraceLn3(J2D_TRACE_INFO, "OGLSD_InitFBObject: w=%d h=%d texid=%d",
|
|
textureWidth, textureHeight, textureID);
|
|
|
|
// initialize framebuffer object
|
|
j2d_glGenFramebuffersEXT(1, &fboTmpID);
|
|
j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboTmpID);
|
|
|
|
// attach color texture to framebuffer object
|
|
j2d_glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
|
|
GL_COLOR_ATTACHMENT0_EXT,
|
|
textureTarget, textureID, 0);
|
|
|
|
// attempt to create a depth renderbuffer of a particular format; we
|
|
// will start with the smallest size and then work our way up
|
|
for (i = 0; i < 3; i++) {
|
|
GLenum error, status;
|
|
GLenum depthFormat = depthFormats[i];
|
|
int depthSize = 16 + (i * 8);
|
|
|
|
// initialize depth renderbuffer
|
|
j2d_glGenRenderbuffersEXT(1, &depthTmpID);
|
|
j2d_glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthTmpID);
|
|
j2d_glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, depthFormat,
|
|
textureWidth, textureHeight);
|
|
|
|
// creation of depth buffer could potentially fail, so check for error
|
|
error = j2d_glGetError();
|
|
if (error != GL_NO_ERROR) {
|
|
J2dTraceLn2(J2D_TRACE_VERBOSE,
|
|
"OGLSD_InitFBObject: could not create depth buffer: depth=%d error=%x",
|
|
depthSize, error);
|
|
j2d_glDeleteRenderbuffersEXT(1, &depthTmpID);
|
|
continue;
|
|
}
|
|
|
|
// attach depth renderbuffer to framebuffer object
|
|
j2d_glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
|
|
GL_DEPTH_ATTACHMENT_EXT,
|
|
GL_RENDERBUFFER_EXT, depthTmpID);
|
|
|
|
// now check for framebuffer "completeness"
|
|
status = j2d_glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
|
|
|
|
if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
|
|
// we found a valid format, so break out of the loop
|
|
J2dTraceLn1(J2D_TRACE_VERBOSE,
|
|
" framebuffer is complete: depth=%d", depthSize);
|
|
foundDepth = JNI_TRUE;
|
|
break;
|
|
} else {
|
|
// this depth format didn't work, so delete and try another format
|
|
J2dTraceLn2(J2D_TRACE_VERBOSE,
|
|
" framebuffer is incomplete: depth=%d status=%x",
|
|
depthSize, status);
|
|
j2d_glDeleteRenderbuffersEXT(1, &depthTmpID);
|
|
}
|
|
}
|
|
|
|
// unbind the texture and framebuffer objects (they will be bound again
|
|
// later as needed)
|
|
j2d_glBindTexture(textureTarget, 0);
|
|
j2d_glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
|
|
j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
|
|
|
if (!foundDepth) {
|
|
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
|
"OGLSD_InitFBObject: could not find valid depth format");
|
|
j2d_glDeleteFramebuffersEXT(1, &fboTmpID);
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
*fbobjectID = fboTmpID;
|
|
*depthID = depthTmpID;
|
|
|
|
return JNI_TRUE;
|
|
}
|
|
|
|
/**
|
|
* Initializes a framebuffer object, using the given width and height as
|
|
* a guide. See OGLSD_InitTextureObject() and OGLSD_InitFBObject()
|
|
* for more information.
|
|
*/
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_sun_java2d_opengl_OGLSurfaceData_initFBObject
|
|
(JNIEnv *env, jobject oglsd,
|
|
jlong pData, jboolean isOpaque,
|
|
jboolean texNonPow2, jboolean texRect,
|
|
jint width, jint height)
|
|
{
|
|
OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData);
|
|
GLuint fbobjectID, depthID;
|
|
|
|
J2dTraceLn2(J2D_TRACE_INFO,
|
|
"OGLSurfaceData_initFBObject: w=%d h=%d",
|
|
width, height);
|
|
|
|
if (oglsdo == NULL) {
|
|
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
|
"OGLSurfaceData_initFBObject: ops are null");
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
// initialize color texture object
|
|
if (!OGLSD_InitTextureObject(oglsdo, isOpaque, texNonPow2, texRect,
|
|
width, height))
|
|
{
|
|
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
|
"OGLSurfaceData_initFBObject: could not init texture object");
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
// initialize framebuffer object using color texture created above
|
|
if (!OGLSD_InitFBObject(&fbobjectID, &depthID,
|
|
oglsdo->textureID, oglsdo->textureTarget,
|
|
oglsdo->textureWidth, oglsdo->textureHeight))
|
|
{
|
|
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
|
"OGLSurfaceData_initFBObject: could not init fbobject");
|
|
j2d_glDeleteTextures(1, &oglsdo->textureID);
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
oglsdo->drawableType = OGLSD_FBOBJECT;
|
|
// other fields (e.g. width, height) are set in OGLSD_InitTextureObject()
|
|
oglsdo->fbobjectID = fbobjectID;
|
|
oglsdo->depthID = depthID;
|
|
|
|
OGLSD_SetNativeDimensions(env, oglsdo,
|
|
oglsdo->textureWidth, oglsdo->textureHeight);
|
|
|
|
// framebuffer objects differ from other OpenGL surfaces in that the
|
|
// value passed to glRead/DrawBuffer() must be GL_COLOR_ATTACHMENTn_EXT,
|
|
// rather than GL_FRONT (or GL_BACK)
|
|
oglsdo->activeBuffer = GL_COLOR_ATTACHMENT0_EXT;
|
|
|
|
return JNI_TRUE;
|
|
}
|
|
|
|
/**
|
|
* Initializes a surface in the backbuffer of a given double-buffered
|
|
* onscreen window for use in a BufferStrategy.Flip situation. The bounds of
|
|
* the backbuffer surface should always be kept in sync with the bounds of
|
|
* the underlying native window.
|
|
*/
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_sun_java2d_opengl_OGLSurfaceData_initFlipBackbuffer
|
|
(JNIEnv *env, jobject oglsd,
|
|
jlong pData)
|
|
{
|
|
OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData);
|
|
|
|
J2dTraceLn(J2D_TRACE_INFO, "OGLSurfaceData_initFlipBackbuffer");
|
|
|
|
if (oglsdo == NULL) {
|
|
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
|
"OGLSurfaceData_initFlipBackbuffer: ops are null");
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
if (oglsdo->drawableType == OGLSD_UNDEFINED) {
|
|
if (!OGLSD_InitOGLWindow(env, oglsdo)) {
|
|
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
|
"OGLSurfaceData_initFlipBackbuffer: could not init window");
|
|
return JNI_FALSE;
|
|
}
|
|
}
|
|
|
|
if (oglsdo->drawableType != OGLSD_WINDOW) {
|
|
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
|
"OGLSurfaceData_initFlipBackbuffer: drawable is not a window");
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
oglsdo->drawableType = OGLSD_FLIP_BACKBUFFER;
|
|
// x/yOffset have already been set in OGLSD_InitOGLWindow()...
|
|
// REMIND: for some reason, flipping won't work properly on IFB unless we
|
|
// explicitly use BACK_LEFT rather than BACK...
|
|
oglsdo->activeBuffer = GL_BACK_LEFT;
|
|
|
|
OGLSD_SetNativeDimensions(env, oglsdo, oglsdo->width, oglsdo->height);
|
|
|
|
return JNI_TRUE;
|
|
}
|
|
|
|
JNIEXPORT jint JNICALL
|
|
Java_sun_java2d_opengl_OGLSurfaceData_getTextureTarget
|
|
(JNIEnv *env, jobject oglsd,
|
|
jlong pData)
|
|
{
|
|
OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData);
|
|
|
|
J2dTraceLn(J2D_TRACE_INFO, "OGLSurfaceData_getTextureTarget");
|
|
|
|
if (oglsdo == NULL) {
|
|
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
|
"OGLSurfaceData_getTextureTarget: ops are null");
|
|
return 0;
|
|
}
|
|
|
|
return (jint)oglsdo->textureTarget;
|
|
}
|
|
|
|
JNIEXPORT jint JNICALL
|
|
Java_sun_java2d_opengl_OGLSurfaceData_getTextureID
|
|
(JNIEnv *env, jobject oglsd,
|
|
jlong pData)
|
|
{
|
|
OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData);
|
|
|
|
J2dTraceLn(J2D_TRACE_INFO, "OGLSurfaceData_getTextureID");
|
|
|
|
if (oglsdo == NULL) {
|
|
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
|
"OGLSurfaceData_getTextureID: ops are null");
|
|
return 0L;
|
|
}
|
|
|
|
return (jint)oglsdo->textureID;
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_sun_java2d_opengl_OGLSurfaceData_loadNativeRasterWithRects
|
|
(JNIEnv *env, jclass clazz,
|
|
jlong sdops, jlong pRaster, jint width, jint height, jlong pRects, jint rectsCount)
|
|
{
|
|
OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(sdops);
|
|
if (oglsdo == NULL || pRaster == 0) {
|
|
J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSurfaceData_loadNativeRasterWithRects: params are null");
|
|
return JNI_FALSE;
|
|
}
|
|
//fprintf(stderr, "OGLSurfaceData_loadNativeRasterWithRects: ops=%p r=%p rCount=%d tt=%d texId=%d\n", (void*)sdops, (void*)pRaster, rectsCount, oglsdo->textureTarget, oglsdo->textureID);
|
|
|
|
// Set state.
|
|
OGLPixelFormat pf = PixelFormats[1];
|
|
const int viaTexSubImage = oglsdo->drawableType != OGLSD_FBOBJECT;
|
|
// NOTE: both types works correctly under OSX (probably need to choose the fastest one)
|
|
if (viaTexSubImage) {
|
|
J2dTraceLn(J2D_TRACE_VERBOSE, "OGLSurfaceData_loadNativeRasterWithRects: via glTexSubImage2D");
|
|
j2d_glEnable(GL_TEXTURE_2D);
|
|
j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
|
|
j2d_glBindTexture(GL_TEXTURE_2D, oglsdo->textureID);
|
|
} else {
|
|
J2dTraceLn(J2D_TRACE_VERBOSE, "OGLSurfaceData_loadNativeRasterWithRects: via glDrawPix (i.e. OGLBlitSwToSurface)");
|
|
}
|
|
|
|
// Save GL context
|
|
GLint pv[4];
|
|
glGetIntegerv(GL_VIEWPORT, pv);
|
|
j2d_glViewport(0, 0, width, height);
|
|
|
|
j2d_glMatrixMode(GL_MODELVIEW);
|
|
j2d_glPushMatrix();
|
|
j2d_glLoadIdentity();
|
|
|
|
j2d_glMatrixMode(GL_PROJECTION);
|
|
j2d_glPushMatrix();
|
|
j2d_glLoadIdentity();
|
|
j2d_glOrtho(0.0, (GLdouble)width, (GLdouble)height, 0.0, -1.0, 1.0);
|
|
|
|
const GLboolean scissorEnabled = j2d_glIsEnabled(GL_SCISSOR_TEST);
|
|
const GLboolean depthEnabled = j2d_glIsEnabled(GL_DEPTH_TEST);
|
|
const GLboolean blendEnabled = j2d_glIsEnabled(GL_BLEND);
|
|
j2d_glDisable(GL_SCISSOR_TEST);
|
|
j2d_glDisable(GL_DEPTH_TEST);
|
|
j2d_glDisable(GL_BLEND);
|
|
|
|
// Render.
|
|
if (pRects == 0 || rectsCount < 1) {
|
|
J2dTraceLn(J2D_TRACE_VERBOSE, "OGLSurfaceData_loadNativeRasterWithRects: do full copy of raster:");
|
|
//unsigned char * r = (unsigned char *)pRaster;
|
|
//fprintf(stderr, "\t %d,%d,%d,%d,%d,%d,%d,%d....\n", r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7]);
|
|
if (viaTexSubImage) {
|
|
j2d_glTexSubImage2D(oglsdo->textureTarget, 0,
|
|
0, 0, width, height,
|
|
pf.format, pf.type, (GLvoid*)pRaster);
|
|
} else {
|
|
OGLBlitRasterToSurface(oglsdo, pRaster, width, height, &pf,
|
|
0, 0, width, height,
|
|
0, 0, width, height); }
|
|
} else {
|
|
int32_t *pr = (int32_t *) pRects;
|
|
for (int c = 0; c < rectsCount; ++c) {
|
|
int32_t x = *(pr++);
|
|
int32_t y = *(pr++);
|
|
int32_t w = *(pr++);
|
|
int32_t h = *(pr++);
|
|
if (viaTexSubImage) {
|
|
const GLvoid *srcBytes = (char *)pRaster + y*width*4 + x*4;
|
|
//fprintf(stderr, "\t[%d, %d, %d, %d] %d\n", x, y, w, h, (int)((char*)srcBytes - (char*)pRaster));
|
|
j2d_glTexSubImage2D(oglsdo->textureTarget, 0,
|
|
x, y, w, h,
|
|
pf.format, pf.type, srcBytes);
|
|
} else {
|
|
OGLBlitRasterToSurface(oglsdo, pRaster, width, height, &pf,
|
|
x, y, x + w, y + h,
|
|
x, y, x + w, y + h);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Restore GL context
|
|
if (viaTexSubImage) {
|
|
j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
|
}
|
|
|
|
j2d_glMatrixMode(GL_MODELVIEW);
|
|
j2d_glPopMatrix();
|
|
j2d_glMatrixMode(GL_PROJECTION);
|
|
j2d_glPopMatrix();
|
|
|
|
j2d_glViewport(pv[0], pv[1], (GLsizei)pv[2], (GLsizei)pv[3]);
|
|
|
|
if (scissorEnabled)
|
|
j2d_glEnable(GL_SCISSOR_TEST);
|
|
if (depthEnabled)
|
|
j2d_glEnable(GL_DEPTH_TEST);
|
|
if (blendEnabled)
|
|
j2d_glEnable(GL_BLEND);
|
|
|
|
return JNI_TRUE;
|
|
}
|
|
|
|
|
|
/**
|
|
* Initializes nativeWidth/Height fields of the surfaceData object with
|
|
* passed arguments.
|
|
*/
|
|
void
|
|
OGLSD_SetNativeDimensions(JNIEnv *env, OGLSDOps *oglsdo,
|
|
jint width, jint height)
|
|
{
|
|
jobject sdObject;
|
|
|
|
sdObject = (*env)->NewLocalRef(env, oglsdo->sdOps.sdObject);
|
|
if (sdObject == NULL) {
|
|
return;
|
|
}
|
|
|
|
JNU_SetFieldByName(env, NULL, sdObject, "nativeWidth", "I", width);
|
|
if (!((*env)->ExceptionOccurred(env))) {
|
|
JNU_SetFieldByName(env, NULL, sdObject, "nativeHeight", "I", height);
|
|
}
|
|
|
|
(*env)->DeleteLocalRef(env, sdObject);
|
|
}
|
|
|
|
/**
|
|
* Deletes native OpenGL resources associated with this surface.
|
|
*/
|
|
void
|
|
OGLSD_Delete(JNIEnv *env, OGLSDOps *oglsdo)
|
|
{
|
|
J2dTraceLn1(J2D_TRACE_INFO, "OGLSD_Delete: type=%d",
|
|
oglsdo->drawableType);
|
|
|
|
if (oglsdo->drawableType == OGLSD_TEXTURE) {
|
|
if (oglsdo->textureID != 0) {
|
|
j2d_glDeleteTextures(1, &oglsdo->textureID);
|
|
oglsdo->textureID = 0;
|
|
}
|
|
} else if (oglsdo->drawableType == OGLSD_FBOBJECT) {
|
|
if (oglsdo->textureID != 0) {
|
|
j2d_glDeleteTextures(1, &oglsdo->textureID);
|
|
oglsdo->textureID = 0;
|
|
}
|
|
if (oglsdo->depthID != 0) {
|
|
j2d_glDeleteRenderbuffersEXT(1, &oglsdo->depthID);
|
|
oglsdo->depthID = 0;
|
|
}
|
|
if (oglsdo->fbobjectID != 0) {
|
|
j2d_glDeleteFramebuffersEXT(1, &oglsdo->fbobjectID);
|
|
oglsdo->fbobjectID = 0;
|
|
}
|
|
} else {
|
|
// dispose windowing system resources (pbuffer, pixmap, etc)
|
|
OGLSD_DestroyOGLSurface(env, oglsdo);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This is the implementation of the general DisposeFunc defined in
|
|
* SurfaceData.h and used by the Disposer mechanism. It first flushes all
|
|
* native OpenGL resources and then frees any memory allocated within the
|
|
* native OGLSDOps structure.
|
|
*/
|
|
void
|
|
OGLSD_Dispose(JNIEnv *env, SurfaceDataOps *ops)
|
|
{
|
|
OGLSDOps *oglsdo = (OGLSDOps *)ops;
|
|
jobject graphicsConfig = oglsdo->graphicsConfig;
|
|
|
|
JNU_CallStaticMethodByName(env, NULL, "sun/java2d/opengl/OGLSurfaceData",
|
|
"dispose",
|
|
"(JLsun/java2d/opengl/OGLGraphicsConfig;)V",
|
|
ptr_to_jlong(ops), graphicsConfig);
|
|
(*env)->DeleteGlobalRef(env, graphicsConfig);
|
|
oglsdo->graphicsConfig = NULL;
|
|
}
|
|
|
|
/**
|
|
* This is the implementation of the general surface LockFunc defined in
|
|
* SurfaceData.h.
|
|
*/
|
|
jint
|
|
OGLSD_Lock(JNIEnv *env,
|
|
SurfaceDataOps *ops,
|
|
SurfaceDataRasInfo *pRasInfo,
|
|
jint lockflags)
|
|
{
|
|
JNU_ThrowInternalError(env, "OGLSD_Lock not implemented!");
|
|
return SD_FAILURE;
|
|
}
|
|
|
|
/**
|
|
* This is the implementation of the general GetRasInfoFunc defined in
|
|
* SurfaceData.h.
|
|
*/
|
|
void
|
|
OGLSD_GetRasInfo(JNIEnv *env,
|
|
SurfaceDataOps *ops,
|
|
SurfaceDataRasInfo *pRasInfo)
|
|
{
|
|
JNU_ThrowInternalError(env, "OGLSD_GetRasInfo not implemented!");
|
|
}
|
|
|
|
/**
|
|
* This is the implementation of the general surface UnlockFunc defined in
|
|
* SurfaceData.h.
|
|
*/
|
|
void
|
|
OGLSD_Unlock(JNIEnv *env,
|
|
SurfaceDataOps *ops,
|
|
SurfaceDataRasInfo *pRasInfo)
|
|
{
|
|
JNU_ThrowInternalError(env, "OGLSD_Unlock not implemented!");
|
|
}
|
|
|
|
#endif /* !HEADLESS */
|