Path: blob/master/src/java.desktop/windows/native/libawt/java2d/opengl/WGLSurfaceData.c
41159 views
/*1* Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include <stdlib.h>2627#include "sun_java2d_opengl_WGLSurfaceData.h"2829#include "jni.h"30#include "jlong.h"31#include "jni_util.h"32#include "sizecalc.h"33#include "OGLRenderQueue.h"34#include "WGLGraphicsConfig.h"35#include "WGLSurfaceData.h"3637/**38* The methods in this file implement the native windowing system specific39* layer (WGL) for the OpenGL-based Java 2D pipeline.40*/4142extern LockFunc OGLSD_Lock;43extern GetRasInfoFunc OGLSD_GetRasInfo;44extern UnlockFunc OGLSD_Unlock;45extern DisposeFunc OGLSD_Dispose;4647extern OGLPixelFormat PixelFormats[];48extern void AwtWindow_UpdateWindow(JNIEnv *env, jobject peer,49jint w, jint h, HBITMAP hBitmap);50extern HBITMAP BitmapUtil_CreateBitmapFromARGBPre(int width, int height,51int srcStride,52int* imageData);53extern void AwtComponent_GetInsets(JNIEnv *env, jobject peer, RECT *insets);5455extern void56OGLSD_SetNativeDimensions(JNIEnv *env, OGLSDOps *oglsdo, jint w, jint h);5758JNIEXPORT void JNICALL59Java_sun_java2d_opengl_WGLSurfaceData_initOps(JNIEnv *env, jobject wglsd,60jobject gc, jlong pConfigInfo,61jobject peer, jlong hwnd)62{63gc = (*env)->NewGlobalRef(env, gc);64if (gc == NULL) {65JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed.");66return;67}6869OGLSDOps *oglsdo = (OGLSDOps *)SurfaceData_InitOps(env, wglsd,70sizeof(OGLSDOps));71if (oglsdo == NULL) {72(*env)->DeleteGlobalRef(env, gc);73JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed.");74return;75}76// later the graphicsConfig will be used for deallocation of oglsdo77oglsdo->graphicsConfig = gc;7879WGLSDOps *wglsdo = (WGLSDOps *)malloc(sizeof(WGLSDOps));8081J2dTraceLn(J2D_TRACE_INFO, "WGLSurfaceData_initOps");8283if (wglsdo == NULL) {84JNU_ThrowOutOfMemoryError(env, "creating native wgl ops");85return;86}87if (oglsdo == NULL) {88free(wglsdo);89JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed.");90return;91}9293oglsdo->privOps = wglsdo;9495oglsdo->sdOps.Lock = OGLSD_Lock;96oglsdo->sdOps.GetRasInfo = OGLSD_GetRasInfo;97oglsdo->sdOps.Unlock = OGLSD_Unlock;98oglsdo->sdOps.Dispose = OGLSD_Dispose;99100oglsdo->drawableType = OGLSD_UNDEFINED;101oglsdo->activeBuffer = GL_FRONT;102oglsdo->needsInit = JNI_TRUE;103if (peer != NULL) {104RECT insets;105AwtComponent_GetInsets(env, peer, &insets);106oglsdo->xOffset = -insets.left;107oglsdo->yOffset = -insets.bottom;108} else {109oglsdo->xOffset = 0;110oglsdo->yOffset = 0;111}112113wglsdo->window = (HWND)jlong_to_ptr(hwnd);114wglsdo->configInfo = (WGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);115if (wglsdo->configInfo == NULL) {116free(wglsdo);117JNU_ThrowNullPointerException(env, "Config info is null in initOps");118}119}120121/**122* This function disposes of any native windowing system resources associated123* with this surface.124*/125void126OGLSD_DestroyOGLSurface(JNIEnv *env, OGLSDOps *oglsdo)127{128J2dTraceLn(J2D_TRACE_INFO, "OGLSD_DestroyOGLSurface");129// Window is free'd later by AWT code...130}131132/**133* Makes the given context current to its associated "scratch" surface. If134* the operation is successful, this method will return JNI_TRUE; otherwise,135* returns JNI_FALSE.136*/137static jboolean138WGLSD_MakeCurrentToScratch(JNIEnv *env, OGLContext *oglc)139{140WGLCtxInfo *ctxInfo;141142J2dTraceLn(J2D_TRACE_INFO, "WGLSD_MakeCurrentToScratch");143144if (oglc == NULL) {145J2dRlsTraceLn(J2D_TRACE_ERROR,146"WGLSD_MakeCurrentToScratch: context is null");147return JNI_FALSE;148}149150ctxInfo = (WGLCtxInfo *)oglc->ctxInfo;151if (!j2d_wglMakeCurrent(ctxInfo->scratchSurfaceDC, ctxInfo->context)) {152J2dRlsTraceLn(J2D_TRACE_ERROR,153"WGLSD_MakeCurrentToScratch: could not make current");154return JNI_FALSE;155}156157return JNI_TRUE;158}159160/**161* Makes the given GraphicsConfig's context current to its associated162* "scratch" surface. If there is a problem making the context current,163* this method will return NULL; otherwise, returns a pointer to the164* OGLContext that is associated with the given GraphicsConfig.165*/166OGLContext *167OGLSD_SetScratchSurface(JNIEnv *env, jlong pConfigInfo)168{169WGLGraphicsConfigInfo *wglInfo =170(WGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);171OGLContext *oglc;172173J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SetScratchContext");174175if (wglInfo == NULL) {176J2dRlsTraceLn(J2D_TRACE_ERROR,177"OGLSD_SetScratchContext: wgl config info is null");178return NULL;179}180181oglc = wglInfo->context;182if (!WGLSD_MakeCurrentToScratch(env, oglc)) {183return NULL;184}185186if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) {187// the GL_EXT_framebuffer_object extension is present, so this call188// will ensure that we are bound to the scratch pbuffer (and not189// some other framebuffer object)190j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);191}192193return oglc;194}195196/**197* Makes a context current to the given source and destination198* surfaces. If there is a problem making the context current, this method199* will return NULL; otherwise, returns a pointer to the OGLContext that is200* associated with the destination surface.201*/202OGLContext *203OGLSD_MakeOGLContextCurrent(JNIEnv *env, OGLSDOps *srcOps, OGLSDOps *dstOps)204{205WGLSDOps *srcWGLOps = (WGLSDOps *)srcOps->privOps;206WGLSDOps *dstWGLOps = (WGLSDOps *)dstOps->privOps;207OGLContext *oglc;208WGLCtxInfo *ctxinfo;209HDC srcHDC, dstHDC;210BOOL success;211212J2dTraceLn(J2D_TRACE_INFO, "OGLSD_MakeOGLContextCurrent");213214J2dTraceLn4(J2D_TRACE_VERBOSE, " src: %d %p dst: %d %p",215srcOps->drawableType, srcOps,216dstOps->drawableType, dstOps);217218oglc = dstWGLOps->configInfo->context;219if (oglc == NULL) {220J2dRlsTraceLn(J2D_TRACE_ERROR,221"OGLSD_MakeOGLContextCurrent: context is null");222return NULL;223}224225if (dstOps->drawableType == OGLSD_FBOBJECT) {226OGLContext *currentContext = OGLRenderQueue_GetCurrentContext();227228// first make sure we have a current context (if the context isn't229// already current to some drawable, we will make it current to230// its scratch surface)231if (oglc != currentContext) {232if (!WGLSD_MakeCurrentToScratch(env, oglc)) {233return NULL;234}235}236237// now bind to the fbobject associated with the destination surface;238// this means that all rendering will go into the fbobject destination239// (note that we unbind the currently bound texture first; this is240// recommended procedure when binding an fbobject)241j2d_glBindTexture(dstOps->textureTarget, 0);242j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dstOps->fbobjectID);243244return oglc;245}246247ctxinfo = (WGLCtxInfo *)oglc->ctxInfo;248249// get the hdc for the destination surface250dstHDC = GetDC(dstWGLOps->window);251252// get the hdc for the source surface253// the source will always be equal to the destination in this case254srcHDC = dstHDC;255256// REMIND: in theory we should be able to use wglMakeContextCurrentARB()257// even when the src/dst surfaces are the same, but this causes problems258// on ATI's drivers (see 6525997); for now we will only use it when the259// surfaces are different, otherwise we will use the old260// wglMakeCurrent() approach...261if (srcHDC != dstHDC) {262// use WGL_ARB_make_current_read extension to make context current263success =264j2d_wglMakeContextCurrentARB(dstHDC, srcHDC, ctxinfo->context);265} else {266// use the old approach for making current to the destination267success = j2d_wglMakeCurrent(dstHDC, ctxinfo->context);268}269if (!success) {270J2dRlsTraceLn(J2D_TRACE_ERROR,271"OGLSD_MakeOGLContextCurrent: could not make current");272ReleaseDC(dstWGLOps->window, dstHDC);273return NULL;274}275276if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) {277// the GL_EXT_framebuffer_object extension is present, so we278// must bind to the default (windowing system provided)279// framebuffer280j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);281}282283ReleaseDC(dstWGLOps->window, dstHDC);284285return oglc;286}287288/**289* This function initializes a native window surface and caches the window290* bounds in the given OGLSDOps. Returns JNI_TRUE if the operation was291* successful; JNI_FALSE otherwise.292*/293jboolean294OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo)295{296PIXELFORMATDESCRIPTOR pfd;297WGLSDOps *wglsdo;298WGLGraphicsConfigInfo *wglInfo;299HWND window;300RECT wbounds;301HDC hdc;302303J2dTraceLn(J2D_TRACE_INFO, "OGLSD_InitOGLWindow");304305if (oglsdo == NULL) {306J2dRlsTraceLn(J2D_TRACE_ERROR,307"OGLSD_InitOGLWindow: ops are null");308return JNI_FALSE;309}310311wglsdo = (WGLSDOps *)oglsdo->privOps;312if (wglsdo == NULL) {313J2dRlsTraceLn(J2D_TRACE_ERROR,314"OGLSD_InitOGLWindow: wgl ops are null");315return JNI_FALSE;316}317318wglInfo = wglsdo->configInfo;319if (wglInfo == NULL) {320J2dRlsTraceLn(J2D_TRACE_ERROR,321"OGLSD_InitOGLWindow: graphics config info is null");322return JNI_FALSE;323}324325window = wglsdo->window;326if (!IsWindow(window)) {327J2dRlsTraceLn(J2D_TRACE_ERROR,328"OGLSD_InitOGLWindow: disposed component");329return JNI_FALSE;330}331332GetWindowRect(window, &wbounds);333334hdc = GetDC(window);335if (hdc == 0) {336J2dRlsTraceLn(J2D_TRACE_ERROR,337"OGLSD_InitOGLWindow: invalid hdc");338return JNI_FALSE;339}340341if (!SetPixelFormat(hdc, wglInfo->pixfmt, &pfd)) {342J2dRlsTraceLn(J2D_TRACE_ERROR,343"OGLSD_InitOGLWindow: error setting pixel format");344ReleaseDC(window, hdc);345return JNI_FALSE;346}347348ReleaseDC(window, hdc);349350oglsdo->drawableType = OGLSD_WINDOW;351oglsdo->isOpaque = JNI_TRUE;352oglsdo->width = wbounds.right - wbounds.left;353oglsdo->height = wbounds.bottom - wbounds.top;354wglsdo->pbufferDC = 0;355356J2dTraceLn2(J2D_TRACE_VERBOSE, " created window: w=%d h=%d",357oglsdo->width, oglsdo->height);358359return JNI_TRUE;360}361362void363OGLSD_SwapBuffers(JNIEnv *env, jlong pPeerData)364{365HWND window;366HDC hdc;367368J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SwapBuffers");369370window = AwtComponent_GetHWnd(env, pPeerData);371if (!IsWindow(window)) {372J2dRlsTraceLn(J2D_TRACE_ERROR,373"OGLSD_SwapBuffers: disposed component");374return;375}376377hdc = GetDC(window);378if (hdc == 0) {379J2dRlsTraceLn(J2D_TRACE_ERROR,380"OGLSD_SwapBuffers: invalid hdc");381return;382}383384if (!SwapBuffers(hdc)) {385J2dRlsTraceLn(J2D_TRACE_ERROR,386"OGLSD_SwapBuffers: error in SwapBuffers");387}388389if (!ReleaseDC(window, hdc)) {390J2dRlsTraceLn(J2D_TRACE_ERROR,391"OGLSD_SwapBuffers: error while releasing dc");392}393}394395// needed by Mac OS X port, no-op on other platforms396void397OGLSD_Flush(JNIEnv *env)398{399}400401/*402* Class: sun_java2d_opengl_WGLSurfaceData403* Method: updateWindowAccelImpl404* Signature: (JJII)Z405*/406JNIEXPORT jboolean JNICALL407Java_sun_java2d_opengl_WGLSurfaceData_updateWindowAccelImpl408(JNIEnv *env, jclass clazz, jlong pData, jobject peer, jint w, jint h)409{410OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData);411OGLPixelFormat pf = PixelFormats[0/*PF_INT_ARGB_PRE*/];412HBITMAP hBitmap = NULL;413void *pDst;414jint srcx, srcy, dstx, dsty, width, height;415jint pixelStride = 4;416jint scanStride = pixelStride * w;417418J2dTraceLn(J2D_TRACE_INFO, "WGLSurfaceData_updateWindowAccelImpl");419420if (w <= 0 || h <= 0) {421return JNI_TRUE;422}423if (oglsdo == NULL) {424return JNI_FALSE;425}426RESET_PREVIOUS_OP();427428width = w;429height = h;430srcx = srcy = dstx = dsty = 0;431432pDst = SAFE_SIZE_ARRAY_ALLOC(malloc, height, scanStride);433if (pDst == NULL) {434return JNI_FALSE;435}436ZeroMemory(pDst, height * scanStride);437438// the code below is mostly copied from OGLBlitLoops_SurfaceToSwBlit439440j2d_glPixelStorei(GL_PACK_SKIP_PIXELS, dstx);441j2d_glPixelStorei(GL_PACK_ROW_LENGTH, scanStride / pixelStride);442j2d_glPixelStorei(GL_PACK_ALIGNMENT, pf.alignment);443444// this accounts for lower-left origin of the source region445srcx = oglsdo->xOffset + srcx;446srcy = oglsdo->yOffset + oglsdo->height - (srcy + 1);447// we must read one scanline at a time because there is no way448// to read starting at the top-left corner of the source region449while (height > 0) {450j2d_glPixelStorei(GL_PACK_SKIP_ROWS, dsty);451j2d_glReadPixels(srcx, srcy, width, 1,452pf.format, pf.type, pDst);453srcy--;454dsty++;455height--;456}457458j2d_glPixelStorei(GL_PACK_SKIP_PIXELS, 0);459j2d_glPixelStorei(GL_PACK_SKIP_ROWS, 0);460j2d_glPixelStorei(GL_PACK_ROW_LENGTH, 0);461j2d_glPixelStorei(GL_PACK_ALIGNMENT, 4);462463// the pixels read from the surface are already premultiplied464hBitmap = BitmapUtil_CreateBitmapFromARGBPre(w, h, scanStride,465(int*)pDst);466free(pDst);467468if (hBitmap == NULL) {469return JNI_FALSE;470}471472AwtWindow_UpdateWindow(env, peer, w, h, hBitmap);473474// hBitmap is released in UpdateWindow475476return JNI_TRUE;477}478479480