Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/native/sun/java2d/opengl/WGLSurfaceData.c
32288 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{63OGLSDOps *oglsdo;64WGLSDOps *wglsdo;6566gc = (*env)->NewGlobalRef(env, gc);67if (gc == NULL) {68JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed.");69return;70}7172oglsdo = (OGLSDOps *)SurfaceData_InitOps(env, wglsd,73sizeof(OGLSDOps));74if (oglsdo == NULL) {75(*env)->DeleteGlobalRef(env, gc);76JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed.");77return;78}79// later the graphicsConfig will be used for deallocation of oglsdo80oglsdo->graphicsConfig = gc;8182wglsdo = (WGLSDOps *)malloc(sizeof(WGLSDOps));8384J2dTraceLn(J2D_TRACE_INFO, "WGLSurfaceData_initOps");8586if (wglsdo == NULL) {87JNU_ThrowOutOfMemoryError(env, "creating native wgl ops");88return;89}90if (oglsdo == NULL) {91free(wglsdo);92JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed.");93return;94}9596oglsdo->privOps = wglsdo;9798oglsdo->sdOps.Lock = OGLSD_Lock;99oglsdo->sdOps.GetRasInfo = OGLSD_GetRasInfo;100oglsdo->sdOps.Unlock = OGLSD_Unlock;101oglsdo->sdOps.Dispose = OGLSD_Dispose;102103oglsdo->drawableType = OGLSD_UNDEFINED;104oglsdo->activeBuffer = GL_FRONT;105oglsdo->needsInit = JNI_TRUE;106if (peer != NULL) {107RECT insets;108AwtComponent_GetInsets(env, peer, &insets);109oglsdo->xOffset = -insets.left;110oglsdo->yOffset = -insets.bottom;111} else {112oglsdo->xOffset = 0;113oglsdo->yOffset = 0;114}115116wglsdo->window = (HWND)jlong_to_ptr(hwnd);117wglsdo->configInfo = (WGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);118if (wglsdo->configInfo == NULL) {119free(wglsdo);120JNU_ThrowNullPointerException(env, "Config info is null in initOps");121}122}123124/**125* This function disposes of any native windowing system resources associated126* with this surface. For instance, if the given OGLSDOps is of type127* OGLSD_PBUFFER, this method implementation will destroy the actual pbuffer128* surface.129*/130void131OGLSD_DestroyOGLSurface(JNIEnv *env, OGLSDOps *oglsdo)132{133WGLSDOps *wglsdo = (WGLSDOps *)oglsdo->privOps;134135J2dTraceLn(J2D_TRACE_INFO, "OGLSD_DestroyOGLSurface");136137if (oglsdo->drawableType == OGLSD_PBUFFER) {138if (wglsdo->pbuffer != 0) {139if (wglsdo->pbufferDC != 0) {140j2d_wglReleasePbufferDCARB(wglsdo->pbuffer,141wglsdo->pbufferDC);142wglsdo->pbufferDC = 0;143}144j2d_wglDestroyPbufferARB(wglsdo->pbuffer);145wglsdo->pbuffer = 0;146}147}148}149150/**151* Makes the given context current to its associated "scratch" surface. If152* the operation is successful, this method will return JNI_TRUE; otherwise,153* returns JNI_FALSE.154*/155static jboolean156WGLSD_MakeCurrentToScratch(JNIEnv *env, OGLContext *oglc)157{158WGLCtxInfo *ctxInfo;159160J2dTraceLn(J2D_TRACE_INFO, "WGLSD_MakeCurrentToScratch");161162if (oglc == NULL) {163J2dRlsTraceLn(J2D_TRACE_ERROR,164"WGLSD_MakeCurrentToScratch: context is null");165return JNI_FALSE;166}167168ctxInfo = (WGLCtxInfo *)oglc->ctxInfo;169if (!j2d_wglMakeCurrent(ctxInfo->scratchSurfaceDC, ctxInfo->context)) {170J2dRlsTraceLn(J2D_TRACE_ERROR,171"WGLSD_MakeCurrentToScratch: could not make current");172return JNI_FALSE;173}174175return JNI_TRUE;176}177178/**179* Makes the given GraphicsConfig's context current to its associated180* "scratch" surface. If there is a problem making the context current,181* this method will return NULL; otherwise, returns a pointer to the182* OGLContext that is associated with the given GraphicsConfig.183*/184OGLContext *185OGLSD_SetScratchSurface(JNIEnv *env, jlong pConfigInfo)186{187WGLGraphicsConfigInfo *wglInfo =188(WGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);189OGLContext *oglc;190191J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SetScratchContext");192193if (wglInfo == NULL) {194J2dRlsTraceLn(J2D_TRACE_ERROR,195"OGLSD_SetScratchContext: wgl config info is null");196return NULL;197}198199oglc = wglInfo->context;200if (!WGLSD_MakeCurrentToScratch(env, oglc)) {201return NULL;202}203204if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) {205// the GL_EXT_framebuffer_object extension is present, so this call206// will ensure that we are bound to the scratch pbuffer (and not207// some other framebuffer object)208j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);209}210211return oglc;212}213214/**215* Makes a context current to the given source and destination216* surfaces. If there is a problem making the context current, this method217* will return NULL; otherwise, returns a pointer to the OGLContext that is218* associated with the destination surface.219*/220OGLContext *221OGLSD_MakeOGLContextCurrent(JNIEnv *env, OGLSDOps *srcOps, OGLSDOps *dstOps)222{223WGLSDOps *srcWGLOps = (WGLSDOps *)srcOps->privOps;224WGLSDOps *dstWGLOps = (WGLSDOps *)dstOps->privOps;225OGLContext *oglc;226WGLCtxInfo *ctxinfo;227HDC srcHDC, dstHDC;228BOOL success;229230J2dTraceLn(J2D_TRACE_INFO, "OGLSD_MakeOGLContextCurrent");231232J2dTraceLn4(J2D_TRACE_VERBOSE, " src: %d %p dst: %d %p",233srcOps->drawableType, srcOps,234dstOps->drawableType, dstOps);235236oglc = dstWGLOps->configInfo->context;237if (oglc == NULL) {238J2dRlsTraceLn(J2D_TRACE_ERROR,239"OGLSD_MakeOGLContextCurrent: context is null");240return NULL;241}242243if (dstOps->drawableType == OGLSD_FBOBJECT) {244OGLContext *currentContext = OGLRenderQueue_GetCurrentContext();245246// first make sure we have a current context (if the context isn't247// already current to some drawable, we will make it current to248// its scratch surface)249if (oglc != currentContext) {250if (!WGLSD_MakeCurrentToScratch(env, oglc)) {251return NULL;252}253}254255// now bind to the fbobject associated with the destination surface;256// this means that all rendering will go into the fbobject destination257// (note that we unbind the currently bound texture first; this is258// recommended procedure when binding an fbobject)259j2d_glBindTexture(dstOps->textureTarget, 0);260j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dstOps->fbobjectID);261262return oglc;263}264265ctxinfo = (WGLCtxInfo *)oglc->ctxInfo;266267// get the hdc for the destination surface268if (dstOps->drawableType == OGLSD_PBUFFER) {269dstHDC = dstWGLOps->pbufferDC;270} else {271dstHDC = GetDC(dstWGLOps->window);272}273274// get the hdc for the source surface275if (srcOps->drawableType == OGLSD_PBUFFER) {276srcHDC = srcWGLOps->pbufferDC;277} else {278// the source will always be equal to the destination in this case279srcHDC = dstHDC;280}281282// REMIND: in theory we should be able to use wglMakeContextCurrentARB()283// even when the src/dst surfaces are the same, but this causes problems284// on ATI's drivers (see 6525997); for now we will only use it when the285// surfaces are different, otherwise we will use the old286// wglMakeCurrent() approach...287if (srcHDC != dstHDC) {288// use WGL_ARB_make_current_read extension to make context current289success =290j2d_wglMakeContextCurrentARB(dstHDC, srcHDC, ctxinfo->context);291} else {292// use the old approach for making current to the destination293success = j2d_wglMakeCurrent(dstHDC, ctxinfo->context);294}295if (!success) {296J2dRlsTraceLn(J2D_TRACE_ERROR,297"OGLSD_MakeOGLContextCurrent: could not make current");298if (dstOps->drawableType != OGLSD_PBUFFER) {299ReleaseDC(dstWGLOps->window, dstHDC);300}301return NULL;302}303304if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) {305// the GL_EXT_framebuffer_object extension is present, so we306// must bind to the default (windowing system provided)307// framebuffer308j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);309}310311if (dstOps->drawableType != OGLSD_PBUFFER) {312ReleaseDC(dstWGLOps->window, dstHDC);313}314315return oglc;316}317318/**319* This function initializes a native window surface and caches the window320* bounds in the given OGLSDOps. Returns JNI_TRUE if the operation was321* successful; JNI_FALSE otherwise.322*/323jboolean324OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo)325{326PIXELFORMATDESCRIPTOR pfd;327WGLSDOps *wglsdo;328WGLGraphicsConfigInfo *wglInfo;329HWND window;330RECT wbounds;331HDC hdc;332333J2dTraceLn(J2D_TRACE_INFO, "OGLSD_InitOGLWindow");334335if (oglsdo == NULL) {336J2dRlsTraceLn(J2D_TRACE_ERROR,337"OGLSD_InitOGLWindow: ops are null");338return JNI_FALSE;339}340341wglsdo = (WGLSDOps *)oglsdo->privOps;342if (wglsdo == NULL) {343J2dRlsTraceLn(J2D_TRACE_ERROR,344"OGLSD_InitOGLWindow: wgl ops are null");345return JNI_FALSE;346}347348wglInfo = wglsdo->configInfo;349if (wglInfo == NULL) {350J2dRlsTraceLn(J2D_TRACE_ERROR,351"OGLSD_InitOGLWindow: graphics config info is null");352return JNI_FALSE;353}354355window = wglsdo->window;356if (!IsWindow(window)) {357J2dRlsTraceLn(J2D_TRACE_ERROR,358"OGLSD_InitOGLWindow: disposed component");359return JNI_FALSE;360}361362GetWindowRect(window, &wbounds);363364hdc = GetDC(window);365if (hdc == 0) {366J2dRlsTraceLn(J2D_TRACE_ERROR,367"OGLSD_InitOGLWindow: invalid hdc");368return JNI_FALSE;369}370371if (!SetPixelFormat(hdc, wglInfo->pixfmt, &pfd)) {372J2dRlsTraceLn(J2D_TRACE_ERROR,373"OGLSD_InitOGLWindow: error setting pixel format");374ReleaseDC(window, hdc);375return JNI_FALSE;376}377378ReleaseDC(window, hdc);379380oglsdo->drawableType = OGLSD_WINDOW;381oglsdo->isOpaque = JNI_TRUE;382oglsdo->width = wbounds.right - wbounds.left;383oglsdo->height = wbounds.bottom - wbounds.top;384wglsdo->pbufferDC = 0;385386J2dTraceLn2(J2D_TRACE_VERBOSE, " created window: w=%d h=%d",387oglsdo->width, oglsdo->height);388389return JNI_TRUE;390}391392JNIEXPORT jboolean JNICALL393Java_sun_java2d_opengl_WGLSurfaceData_initPbuffer394(JNIEnv *env, jobject wglsd,395jlong pData, jlong pConfigInfo,396jboolean isOpaque,397jint width, jint height)398{399int attrKeys[] = {400WGL_MAX_PBUFFER_WIDTH_ARB,401WGL_MAX_PBUFFER_HEIGHT_ARB,402};403int attrVals[2];404int pbAttrList[] = { 0 };405OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData);406WGLGraphicsConfigInfo *wglInfo =407(WGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);408WGLSDOps *wglsdo;409HWND hwnd;410HDC hdc, pbufferDC;411HPBUFFERARB pbuffer;412int maxWidth, maxHeight;413int actualWidth, actualHeight;414415J2dTraceLn3(J2D_TRACE_INFO,416"WGLSurfaceData_initPbuffer: w=%d h=%d opq=%d",417width, height, isOpaque);418419if (oglsdo == NULL) {420J2dRlsTraceLn(J2D_TRACE_ERROR,421"WGLSurfaceData_initPbuffer: ops are null");422return JNI_FALSE;423}424425wglsdo = (WGLSDOps *)oglsdo->privOps;426if (wglsdo == NULL) {427J2dRlsTraceLn(J2D_TRACE_ERROR,428"WGLSurfaceData_initPbuffer: wgl ops are null");429return JNI_FALSE;430}431432if (wglInfo == NULL) {433J2dRlsTraceLn(J2D_TRACE_ERROR,434"WGLSurfaceData_initPbuffer: wgl config info is null");435return JNI_FALSE;436}437438// create a scratch window439hwnd = WGLGC_CreateScratchWindow(wglInfo->screen);440if (hwnd == 0) {441J2dRlsTraceLn(J2D_TRACE_ERROR,442"WGLSurfaceData_initPbuffer: could not create scratch window");443return JNI_FALSE;444}445446// get the HDC for the scratch window447hdc = GetDC(hwnd);448if (hdc == 0) {449J2dRlsTraceLn(J2D_TRACE_ERROR,450"WGLSurfaceData_initPbuffer: could not get dc for scratch window");451DestroyWindow(hwnd);452return JNI_FALSE;453}454455// get the maximum allowable pbuffer dimensions456j2d_wglGetPixelFormatAttribivARB(hdc, wglInfo->pixfmt, 0, 2,457attrKeys, attrVals);458maxWidth = attrVals[0];459maxHeight = attrVals[1];460461J2dTraceLn4(J2D_TRACE_VERBOSE,462" desired pbuffer dimensions: w=%d h=%d maxw=%d maxh=%d",463width, height, maxWidth, maxHeight);464465// if either dimension is 0 or larger than the maximum, we cannot466// allocate a pbuffer with the requested dimensions467if (width == 0 || width > maxWidth ||468height == 0 || height > maxHeight)469{470J2dRlsTraceLn(J2D_TRACE_ERROR,471"WGLSurfaceData_initPbuffer: invalid dimensions");472ReleaseDC(hwnd, hdc);473DestroyWindow(hwnd);474return JNI_FALSE;475}476477pbuffer = j2d_wglCreatePbufferARB(hdc, wglInfo->pixfmt,478width, height, pbAttrList);479480ReleaseDC(hwnd, hdc);481DestroyWindow(hwnd);482483if (pbuffer == 0) {484J2dRlsTraceLn(J2D_TRACE_ERROR,485"WGLSurfaceData_initPbuffer: could not create wgl pbuffer");486return JNI_FALSE;487}488489// note that we get the DC for the pbuffer at creation time, and then490// release the DC when the pbuffer is disposed; the WGL_ARB_pbuffer491// spec is vague about such things, but from past experience we know492// this approach to be more robust than, for example, doing a493// Get/ReleasePbufferDC() everytime we make a context current494pbufferDC = j2d_wglGetPbufferDCARB(pbuffer);495if (pbufferDC == 0) {496J2dRlsTraceLn(J2D_TRACE_ERROR,497"WGLSurfaceData_initPbuffer: could not get dc for pbuffer");498j2d_wglDestroyPbufferARB(pbuffer);499return JNI_FALSE;500}501502// make sure the actual dimensions match those that we requested503j2d_wglQueryPbufferARB(pbuffer, WGL_PBUFFER_WIDTH_ARB, &actualWidth);504j2d_wglQueryPbufferARB(pbuffer, WGL_PBUFFER_HEIGHT_ARB, &actualHeight);505506if (width != actualWidth || height != actualHeight) {507J2dRlsTraceLn2(J2D_TRACE_ERROR,508"WGLSurfaceData_initPbuffer: actual (w=%d h=%d) != requested",509actualWidth, actualHeight);510j2d_wglReleasePbufferDCARB(pbuffer, pbufferDC);511j2d_wglDestroyPbufferARB(pbuffer);512return JNI_FALSE;513}514515oglsdo->drawableType = OGLSD_PBUFFER;516oglsdo->isOpaque = isOpaque;517oglsdo->width = width;518oglsdo->height = height;519wglsdo->pbuffer = pbuffer;520wglsdo->pbufferDC = pbufferDC;521522OGLSD_SetNativeDimensions(env, oglsdo, width, height);523524return JNI_TRUE;525}526527void528OGLSD_SwapBuffers(JNIEnv *env, jlong pPeerData)529{530HWND window;531HDC hdc;532533J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SwapBuffers");534535window = AwtComponent_GetHWnd(env, pPeerData);536if (!IsWindow(window)) {537J2dRlsTraceLn(J2D_TRACE_ERROR,538"OGLSD_SwapBuffers: disposed component");539return;540}541542hdc = GetDC(window);543if (hdc == 0) {544J2dRlsTraceLn(J2D_TRACE_ERROR,545"OGLSD_SwapBuffers: invalid hdc");546return;547}548549if (!SwapBuffers(hdc)) {550J2dRlsTraceLn(J2D_TRACE_ERROR,551"OGLSD_SwapBuffers: error in SwapBuffers");552}553554if (!ReleaseDC(window, hdc)) {555J2dRlsTraceLn(J2D_TRACE_ERROR,556"OGLSD_SwapBuffers: error while releasing dc");557}558}559560// needed by Mac OS X port, no-op on other platforms561void562OGLSD_Flush(JNIEnv *env)563{564}565566/*567* Class: sun_java2d_opengl_WGLSurfaceData568* Method: updateWindowAccelImpl569* Signature: (JJII)Z570*/571JNIEXPORT jboolean JNICALL572Java_sun_java2d_opengl_WGLSurfaceData_updateWindowAccelImpl573(JNIEnv *env, jclass clazz, jlong pData, jobject peer, jint w, jint h)574{575OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData);576OGLPixelFormat pf = PixelFormats[0/*PF_INT_ARGB_PRE*/];577HBITMAP hBitmap = NULL;578void *pDst;579jint srcx, srcy, dstx, dsty, width, height;580jint pixelStride = 4;581jint scanStride = pixelStride * w;582583J2dTraceLn(J2D_TRACE_INFO, "WGLSurfaceData_updateWindowAccelImpl");584585if (w <= 0 || h <= 0) {586return JNI_TRUE;587}588if (oglsdo == NULL) {589return JNI_FALSE;590}591RESET_PREVIOUS_OP();592593width = w;594height = h;595srcx = srcy = dstx = dsty = 0;596597pDst = SAFE_SIZE_ARRAY_ALLOC(malloc, height, scanStride);598if (pDst == NULL) {599return JNI_FALSE;600}601ZeroMemory(pDst, height * scanStride);602603// the code below is mostly copied from OGLBlitLoops_SurfaceToSwBlit604605j2d_glPixelStorei(GL_PACK_SKIP_PIXELS, dstx);606j2d_glPixelStorei(GL_PACK_ROW_LENGTH, scanStride / pixelStride);607j2d_glPixelStorei(GL_PACK_ALIGNMENT, pf.alignment);608609// this accounts for lower-left origin of the source region610srcx = oglsdo->xOffset + srcx;611srcy = oglsdo->yOffset + oglsdo->height - (srcy + 1);612// we must read one scanline at a time because there is no way613// to read starting at the top-left corner of the source region614while (height > 0) {615j2d_glPixelStorei(GL_PACK_SKIP_ROWS, dsty);616j2d_glReadPixels(srcx, srcy, width, 1,617pf.format, pf.type, pDst);618srcy--;619dsty++;620height--;621}622623j2d_glPixelStorei(GL_PACK_SKIP_PIXELS, 0);624j2d_glPixelStorei(GL_PACK_SKIP_ROWS, 0);625j2d_glPixelStorei(GL_PACK_ROW_LENGTH, 0);626j2d_glPixelStorei(GL_PACK_ALIGNMENT, 4);627628// the pixels read from the surface are already premultiplied629hBitmap = BitmapUtil_CreateBitmapFromARGBPre(w, h, scanStride,630(int*)pDst);631free(pDst);632633if (hBitmap == NULL) {634return JNI_FALSE;635}636637AwtWindow_UpdateWindow(env, peer, w, h, hBitmap);638639// hBitmap is released in UpdateWindow640641return JNI_TRUE;642}643644645