Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/native/sun/java2d/d3d/D3DPaints.cpp
32288 views
/*1* Copyright (c) 2007, 2008, 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 <jlong.h>26#include <string.h>2728#include "sun_java2d_d3d_D3DPaints_MultiGradient.h"2930#include "D3DPaints.h"31#include "D3DContext.h"32#include "D3DRenderQueue.h"33#include "D3DSurfaceData.h"3435HRESULT36D3DPaints_ResetPaint(D3DContext *d3dc)37{38jint pixel, paintState;39jubyte ea;40HRESULT res;4142J2dTraceLn(J2D_TRACE_INFO, "D3DPaints_ResetPaint");4344RETURN_STATUS_IF_NULL(d3dc, E_FAIL);4546paintState = d3dc->GetPaintState();47J2dTraceLn1(J2D_TRACE_VERBOSE, " state=%d", paintState);4849res = d3dc->UpdateState(STATE_OTHEROP);5051// disable current complex paint state, if necessary52if (paintState > PAINT_ALPHACOLOR) {53IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice();54DWORD sampler = d3dc->useMask ? 1 : 0;5556d3dc->SetTexture(NULL, sampler);57pd3dDevice->SetSamplerState(sampler,58D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);59pd3dDevice->SetSamplerState(sampler,60D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);61pd3dDevice->SetTextureStageState(sampler,62D3DTSS_TEXCOORDINDEX, sampler);63res = pd3dDevice->SetTextureStageState(sampler,64D3DTSS_TEXTURETRANSFORMFLAGS,65D3DTTFF_DISABLE);6667if (paintState == PAINT_GRADIENT ||68paintState == PAINT_LIN_GRADIENT ||69paintState == PAINT_RAD_GRADIENT)70{71res = pd3dDevice->SetPixelShader(NULL);72}73}7475// set each component of the current color state to the extra alpha76// value, which will effectively apply the extra alpha to each fragment77// in paint/texturing operations78ea = (jubyte)(d3dc->extraAlpha * 0xff + 0.5f);79pixel = (ea << 24) | (ea << 16) | (ea << 8) | (ea << 0);80d3dc->pVCacher->SetColor(pixel);81d3dc->useMask = JNI_FALSE;82d3dc->SetPaintState(-1);83return res;84}8586HRESULT87D3DPaints_SetColor(D3DContext *d3dc, jint pixel)88{89HRESULT res = S_OK;9091J2dTraceLn1(J2D_TRACE_INFO, "D3DPaints_SetColor: pixel=%08x", pixel);9293RETURN_STATUS_IF_NULL(d3dc, E_FAIL);9495// no need to reset the current op state here unless the paint96// state really needs to be changed97if (d3dc->GetPaintState() > PAINT_ALPHACOLOR) {98res = D3DPaints_ResetPaint(d3dc);99}100101d3dc->pVCacher->SetColor(pixel);102d3dc->useMask = JNI_FALSE;103d3dc->SetPaintState(PAINT_ALPHACOLOR);104return res;105}106107/************************* GradientPaint support ****************************/108109HRESULT110D3DPaints_SetGradientPaint(D3DContext *d3dc,111jboolean useMask, jboolean cyclic,112jdouble p0, jdouble p1, jdouble p3,113jint pixel1, jint pixel2)114{115IDirect3DDevice9 *pd3dDevice;116HRESULT res;117118J2dTraceLn(J2D_TRACE_INFO, "D3DPaints_SetGradientPaint");119120RETURN_STATUS_IF_NULL(d3dc, E_FAIL);121D3DPaints_ResetPaint(d3dc);122123#if 0124/*125* REMIND: The following code represents the original fast gradient126* implementation. The problem is that it relies on LINEAR127* texture filtering, which does not provide sufficient128* precision on certain hardware (from ATI, notably), which129* will cause visible banding (e.g. 64 shades of gray between130* black and white, instead of the expected 256 shades. For131* correctness on such hardware, it is necessary to use a132* shader-based approach that does not suffer from these133* precision issues (see below). This original implementation134* is about 16x faster than software, whereas the shader-based135* implementation is only about 4x faster than software (still136* impressive). For simplicity, we will always use the137* shader-based version for now, but in the future we could138* consider using the fast path for certain hardware (that does139* not exhibit the problem) or provide a flag to allow developers140* to control which path we take (for those that are less141* concerned about quality). Therefore, I'll leave this code142* here (currently disabled) for future use.143*/144D3DResource *pGradientTexRes;145IDirect3DTexture9 *pGradientTex;146147// this will initialize the gradient texture, if necessary148res = d3dc->GetResourceManager()->GetGradientTexture(&pGradientTexRes);149RETURN_STATUS_IF_FAILED(res);150151pGradientTex = pGradientTexRes->GetTexture();152153// update the texture containing the gradient colors154{155D3DLOCKED_RECT lockedRect;156res = pGradientTex->LockRect(0, &lockedRect, NULL, D3DLOCK_NOSYSLOCK);157RETURN_STATUS_IF_FAILED(res);158jint *pPix = (jint*)lockedRect.pBits;159pPix[0] = pixel1;160pPix[1] = pixel2;161pGradientTex->UnlockRect(0);162}163164DWORD sampler = useMask ? 1 : 0;165DWORD wrapMode = cyclic ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP;166d3dc->SetTexture(pGradientTex, sampler);167d3dc->UpdateTextureColorState(D3DTA_TEXTURE, sampler);168169pd3dDevice = d3dc->Get3DDevice();170pd3dDevice->SetSamplerState(sampler, D3DSAMP_ADDRESSU, wrapMode);171pd3dDevice->SetSamplerState(sampler, D3DSAMP_ADDRESSV, wrapMode);172pd3dDevice->SetSamplerState(sampler, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);173pd3dDevice->SetSamplerState(sampler, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);174175D3DMATRIX mt;176ZeroMemory(&mt, sizeof(mt));177mt._11 = (float)p0;178mt._21 = (float)p1;179mt._31 = (float)0.0;180mt._41 = (float)p3;181mt._12 = 0.0f;182mt._22 = 1.0f;183mt._32 = 0.0f;184mt._42 = 0.0f;185pd3dDevice->SetTransform(useMask ? D3DTS_TEXTURE1 : D3DTS_TEXTURE0, &mt);186pd3dDevice->SetTextureStageState(sampler, D3DTSS_TEXCOORDINDEX,187D3DTSS_TCI_CAMERASPACEPOSITION);188res = pd3dDevice->SetTextureStageState(sampler,189D3DTSS_TEXTURETRANSFORMFLAGS,190D3DTTFF_COUNT2);191#else192jfloat params[4];193jfloat color[4];194jint flags = 0;195196if (cyclic) flags |= BASIC_GRAD_IS_CYCLIC;197if (useMask) flags |= BASIC_GRAD_USE_MASK;198199// locate/enable the shader program for the given flags200res = d3dc->EnableBasicGradientProgram(flags);201RETURN_STATUS_IF_FAILED(res);202203// update the "uniform" values204params[0] = (jfloat)p0;205params[1] = (jfloat)p1;206params[2] = (jfloat)p3;207params[3] = 0.0f; // unused208pd3dDevice = d3dc->Get3DDevice();209res = pd3dDevice->SetPixelShaderConstantF(0, params, 1);210211color[0] = ((pixel1 >> 16) & 0xff) / 255.0f; // r212color[1] = ((pixel1 >> 8) & 0xff) / 255.0f; // g213color[2] = ((pixel1 >> 0) & 0xff) / 255.0f; // b214color[3] = ((pixel1 >> 24) & 0xff) / 255.0f; // a215res = pd3dDevice->SetPixelShaderConstantF(1, color, 1);216217color[0] = ((pixel2 >> 16) & 0xff) / 255.0f; // r218color[1] = ((pixel2 >> 8) & 0xff) / 255.0f; // g219color[2] = ((pixel2 >> 0) & 0xff) / 255.0f; // b220color[3] = ((pixel2 >> 24) & 0xff) / 255.0f; // a221res = pd3dDevice->SetPixelShaderConstantF(2, color, 1);222223// set up texture coordinate transform with identity matrix, which224// will have the effect of passing the current window-space coordinates225// through to the TEXCOORD0/1 register used by the basic gradient226// pixel shader227DWORD sampler = useMask ? 1 : 0;228D3DMATRIX mt;229ZeroMemory(&mt, sizeof(mt));230mt._11 = 1.0f;231mt._21 = 0.0f;232mt._31 = 0.0f;233mt._41 = 0.0f;234mt._12 = 0.0f;235mt._22 = 1.0f;236mt._32 = 0.0f;237mt._42 = 0.0f;238pd3dDevice->SetTransform(useMask ? D3DTS_TEXTURE1 : D3DTS_TEXTURE0, &mt);239pd3dDevice->SetTextureStageState(sampler, D3DTSS_TEXCOORDINDEX,240D3DTSS_TCI_CAMERASPACEPOSITION);241pd3dDevice->SetTextureStageState(sampler, D3DTSS_TEXTURETRANSFORMFLAGS,242D3DTTFF_COUNT2);243#endif244245// pixel state has been set appropriately in D3DPaints_ResetPaint()246d3dc->useMask = useMask;247d3dc->SetPaintState(PAINT_GRADIENT);248return res;249}250251/************************** TexturePaint support ****************************/252253HRESULT254D3DPaints_SetTexturePaint(D3DContext *d3dc,255jboolean useMask,256jlong pSrcOps, jboolean filter,257jdouble xp0, jdouble xp1, jdouble xp3,258jdouble yp0, jdouble yp1, jdouble yp3)259{260D3DSDOps *srcOps = (D3DSDOps *)jlong_to_ptr(pSrcOps);261IDirect3DDevice9 *pd3dDevice;262HRESULT res;263264J2dTraceLn(J2D_TRACE_INFO, "D3DPaints_SetTexturePaint");265266RETURN_STATUS_IF_NULL(d3dc, E_FAIL);267RETURN_STATUS_IF_NULL(srcOps, E_FAIL);268RETURN_STATUS_IF_NULL(srcOps->pResource, E_FAIL);269D3DPaints_ResetPaint(d3dc);270271DWORD sampler = useMask ? 1 : 0;272DWORD dwFilter = filter ? D3DTEXF_LINEAR : D3DTEXF_POINT;273res = d3dc->SetTexture(srcOps->pResource->GetTexture(), sampler);274d3dc->UpdateTextureColorState(D3DTA_TEXTURE, sampler);275pd3dDevice = d3dc->Get3DDevice();276pd3dDevice->SetSamplerState(sampler, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);277pd3dDevice->SetSamplerState(sampler, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);278pd3dDevice->SetSamplerState(sampler, D3DSAMP_MAGFILTER, dwFilter);279pd3dDevice->SetSamplerState(sampler, D3DSAMP_MINFILTER, dwFilter);280281D3DMATRIX mt;282ZeroMemory(&mt, sizeof(mt));283284// offset by a half texel to correctly map texels to pixels285// m02 = tx * m00 + ty * m01 + m02;286// m12 = tx * m10 + ty * m11 + m12;287jdouble tx = (1 / (2.0f * srcOps->pResource->GetDesc()->Width));288jdouble ty = (1 / (2.0f * srcOps->pResource->GetDesc()->Height));289xp3 = tx * xp0 + ty * xp1 + xp3;290yp3 = tx * yp0 + ty * yp1 + yp3;291292mt._11 = (float)xp0;293mt._21 = (float)xp1;294mt._31 = (float)0.0;295mt._41 = (float)xp3;296mt._12 = (float)yp0;297mt._22 = (float)yp1;298mt._32 = (float)0.0;299mt._42 = (float)yp3;300pd3dDevice->SetTransform(useMask ? D3DTS_TEXTURE1 : D3DTS_TEXTURE0, &mt);301pd3dDevice->SetTextureStageState(sampler, D3DTSS_TEXCOORDINDEX,302D3DTSS_TCI_CAMERASPACEPOSITION);303pd3dDevice->SetTextureStageState(sampler, D3DTSS_TEXTURETRANSFORMFLAGS,304D3DTTFF_COUNT2);305306// pixel state has been set appropriately in D3DPaints_ResetPaint()307d3dc->useMask = useMask;308d3dc->SetPaintState(PAINT_TEXTURE);309return res;310}311312/****************** Shared MultipleGradientPaint support ********************/313314/** Composes the given parameters as flags into the given flags variable.*/315#define COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear) \316do { \317flags |= ((cycleMethod) & MULTI_GRAD_CYCLE_METHOD); \318if (large) flags |= MULTI_GRAD_LARGE; \319if (useMask) flags |= MULTI_GRAD_USE_MASK; \320if (linear) flags |= MULTI_GRAD_LINEAR_RGB; \321} while (0)322323/**324* The maximum number of gradient "stops" supported by the fragment shader325* and related code. When the MULTI_GRAD_LARGE flag is set, we will use326* MAX_FRACTIONS_LARGE; otherwise, we use MAX_FRACTIONS_SMALL. By having327* two separate values, we can have one highly optimized shader (SMALL) that328* supports only a few fractions/colors, and then another, less optimal329* shader that supports more stops.330*/331#define MAX_FRACTIONS \332sun_java2d_d3d_D3DPaints_MultiGradient_MULTI_MAX_FRACTIONS_D3D333#define MAX_FRACTIONS_LARGE MAX_FRACTIONS334#define MAX_FRACTIONS_SMALL 4335336/**337* Called from the D3DPaints_SetLinear/RadialGradientPaint() methods338* in order to setup the fraction/color values that are common to both.339*/340static HRESULT341D3DPaints_SetMultiGradientPaint(D3DContext *d3dc,342jboolean useMask, jint numStops,343void *pFractions, void *pPixels)344{345HRESULT res;346IDirect3DDevice9 *pd3dDevice;347IDirect3DTexture9 *pMultiGradientTex;348D3DResource *pMultiGradientTexRes;349jint maxFractions = (numStops > MAX_FRACTIONS_SMALL) ?350MAX_FRACTIONS_LARGE : MAX_FRACTIONS_SMALL;351jfloat stopVals[MAX_FRACTIONS * 4];352jfloat *fractions = (jfloat *)pFractions;353juint *pixels = (juint *)pPixels;354int i;355int fIndex = 0;356357pd3dDevice = d3dc->Get3DDevice();358359// update the "uniform" fractions and scale factors360for (i = 0; i < maxFractions; i++) {361stopVals[fIndex+0] = (i < numStops) ?362fractions[i] : 0.0f;363stopVals[fIndex+1] = (i < numStops-1) ?3641.0f / (fractions[i+1] - fractions[i]) : 0.0f;365stopVals[fIndex+2] = 0.0f; // unused366stopVals[fIndex+3] = 0.0f; // unused367fIndex += 4;368}369pd3dDevice->SetPixelShaderConstantF(0, stopVals, maxFractions);370371// this will initialize the multi-gradient texture, if necessary372res = d3dc->GetResourceManager()->373GetMultiGradientTexture(&pMultiGradientTexRes);374RETURN_STATUS_IF_FAILED(res);375376pMultiGradientTex = pMultiGradientTexRes->GetTexture();377378// update the texture containing the gradient colors379D3DLOCKED_RECT lockedRect;380res = pMultiGradientTex->LockRect(0, &lockedRect, NULL, D3DLOCK_NOSYSLOCK);381RETURN_STATUS_IF_FAILED(res);382383juint *pPix = (juint*)lockedRect.pBits;384memcpy(pPix, pixels, numStops*sizeof(juint));385if (numStops < MAX_MULTI_GRADIENT_COLORS) {386// when we don't have enough colors to fill the entire387// color gradient, we have to replicate the last color388// in the right-most texel for the NO_CYCLE case where the389// texcoord is sometimes forced to 1.0390pPix[MAX_MULTI_GRADIENT_COLORS-1] = pixels[numStops-1];391}392pMultiGradientTex->UnlockRect(0);393394// set the gradient texture and update relevant state395DWORD sampler = useMask ? 1 : 0;396res = d3dc->SetTexture(pMultiGradientTex, sampler);397d3dc->UpdateTextureColorState(D3DTA_TEXTURE, sampler);398pd3dDevice->SetSamplerState(sampler, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);399pd3dDevice->SetSamplerState(sampler, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);400pd3dDevice->SetSamplerState(sampler, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);401pd3dDevice->SetSamplerState(sampler, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);402403// set up texture coordinate transform with identity matrix, which404// will have the effect of passing the current window-space coordinates405// through to the TEXCOORD0/1 register used by the multi-stop406// gradient pixel shader407D3DMATRIX mt;408ZeroMemory(&mt, sizeof(mt));409mt._11 = 1.0f;410mt._21 = 0.0f;411mt._31 = 0.0f;412mt._41 = 0.0f;413mt._12 = 0.0f;414mt._22 = 1.0f;415mt._32 = 0.0f;416mt._42 = 0.0f;417pd3dDevice->SetTransform(useMask ? D3DTS_TEXTURE1 : D3DTS_TEXTURE0, &mt);418pd3dDevice->SetTextureStageState(sampler, D3DTSS_TEXCOORDINDEX,419D3DTSS_TCI_CAMERASPACEPOSITION);420pd3dDevice->SetTextureStageState(sampler, D3DTSS_TEXTURETRANSFORMFLAGS,421D3DTTFF_COUNT2);422return res;423}424425/********************** LinearGradientPaint support *************************/426427HRESULT428D3DPaints_SetLinearGradientPaint(D3DContext *d3dc, D3DSDOps *dstOps,429jboolean useMask, jboolean linear,430jint cycleMethod, jint numStops,431jfloat p0, jfloat p1, jfloat p3,432void *fractions, void *pixels)433{434HRESULT res;435IDirect3DDevice9 *pd3dDevice;436jfloat params[4];437jboolean large = (numStops > MAX_FRACTIONS_SMALL);438jint flags = 0;439440J2dTraceLn(J2D_TRACE_INFO, "D3DPaints_SetLinearGradientPaint");441442RETURN_STATUS_IF_NULL(d3dc, E_FAIL);443RETURN_STATUS_IF_NULL(dstOps, E_FAIL);444D3DPaints_ResetPaint(d3dc);445446COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear);447448// locate/enable the shader program for the given flags449res = d3dc->EnableLinearGradientProgram(flags);450RETURN_STATUS_IF_FAILED(res);451452// update the common "uniform" values (fractions and colors)453D3DPaints_SetMultiGradientPaint(d3dc, useMask,454numStops, fractions, pixels);455456// update the other "uniform" values457params[0] = p0;458params[1] = p1;459params[2] = p3;460params[3] = 0.0f; // unused461pd3dDevice = d3dc->Get3DDevice();462res = pd3dDevice->SetPixelShaderConstantF(16, params, 1);463464// pixel state has been set appropriately in D3DPaints_ResetPaint()465d3dc->useMask = useMask;466d3dc->SetPaintState(PAINT_LIN_GRADIENT);467return res;468}469470/********************** RadialGradientPaint support *************************/471472HRESULT473D3DPaints_SetRadialGradientPaint(D3DContext *d3dc, D3DSDOps *dstOps,474jboolean useMask, jboolean linear,475jint cycleMethod, jint numStops,476jfloat m00, jfloat m01, jfloat m02,477jfloat m10, jfloat m11, jfloat m12,478jfloat focusX,479void *fractions, void *pixels)480{481HRESULT res;482IDirect3DDevice9 *pd3dDevice;483jfloat denom, inv_denom;484jfloat params[4];485jboolean large = (numStops > MAX_FRACTIONS_SMALL);486jint flags = 0;487488J2dTraceLn(J2D_TRACE_INFO, "D3DPaints_SetRadialGradientPaint");489490RETURN_STATUS_IF_NULL(d3dc, E_FAIL);491RETURN_STATUS_IF_NULL(dstOps, E_FAIL);492D3DPaints_ResetPaint(d3dc);493494COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear);495496// locate/enable the shader program for the given flags497res = d3dc->EnableRadialGradientProgram(flags);498RETURN_STATUS_IF_FAILED(res);499500// update the common "uniform" values (fractions and colors)501D3DPaints_SetMultiGradientPaint(d3dc, useMask,502numStops, fractions, pixels);503504// update the other "uniform" values505params[0] = m00;506params[1] = m01;507params[2] = m02;508params[3] = 0.0f; // unused509pd3dDevice = d3dc->Get3DDevice();510pd3dDevice->SetPixelShaderConstantF(16, params, 1);511512params[0] = m10;513params[1] = m11;514params[2] = m12;515params[3] = 0.0f; // unused516pd3dDevice->SetPixelShaderConstantF(17, params, 1);517518// pack a few unrelated, precalculated values into a single float4519denom = 1.0f - (focusX * focusX);520inv_denom = 1.0f / denom;521params[0] = focusX;522params[1] = denom;523params[2] = inv_denom;524params[3] = 0.0f; // unused525res = pd3dDevice->SetPixelShaderConstantF(18, params, 1);526527// pixel state has been set appropriately in D3DPaints_ResetPaint()528d3dc->useMask = useMask;529d3dc->SetPaintState(PAINT_RAD_GRADIENT);530return res;531}532533534