430N/A/*
2362N/A * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.
430N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
430N/A *
430N/A * This code is free software; you can redistribute it and/or modify it
430N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
430N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
430N/A *
430N/A * This code is distributed in the hope that it will be useful, but WITHOUT
430N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
430N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
430N/A * version 2 for more details (a copy is included in the LICENSE file that
430N/A * accompanied this code).
430N/A *
430N/A * You should have received a copy of the GNU General Public License version
430N/A * 2 along with this work; if not, write to the Free Software Foundation,
430N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
430N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
430N/A */
430N/A
430N/A#include <jlong.h>
430N/A
430N/A#include "D3DBufImgOps.h"
430N/A#include "D3DContext.h"
430N/A#include "D3DRenderQueue.h"
430N/A#include "D3DSurfaceData.h"
430N/A#include "GraphicsPrimitiveMgr.h"
430N/A
430N/A/**************************** ConvolveOp support ****************************/
430N/A
430N/A/**
430N/A * The maximum kernel size supported by the ConvolveOp shader.
430N/A */
430N/A#define MAX_KERNEL_SIZE 25
430N/A
430N/AHRESULT
430N/AD3DBufImgOps_EnableConvolveOp(D3DContext *d3dc, jlong pSrcOps,
430N/A jboolean edgeZeroFill,
430N/A jint kernelWidth, jint kernelHeight,
430N/A unsigned char *kernel)
430N/A{
430N/A HRESULT res;
430N/A IDirect3DDevice9 *pd3dDevice;
430N/A D3DSDOps *srcOps = (D3DSDOps *)jlong_to_ptr(pSrcOps);
430N/A jint kernelSize = kernelWidth * kernelHeight;
430N/A jint texW, texH;
430N/A jfloat xoff, yoff;
430N/A jfloat edgeX, edgeY;
430N/A jfloat imgEdge[4];
430N/A jfloat kernelVals[MAX_KERNEL_SIZE*4];
430N/A jint i, j, kIndex;
430N/A jint flags = 0;
430N/A
430N/A J2dTraceLn2(J2D_TRACE_INFO,
430N/A "D3DBufImgOps_EnableConvolveOp: kernelW=%d kernelH=%d",
430N/A kernelWidth, kernelHeight);
430N/A
430N/A RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
430N/A RETURN_STATUS_IF_NULL(srcOps, E_FAIL);
430N/A
430N/A d3dc->UpdateState(STATE_CHANGE);
430N/A
430N/A // texcoords are specified in the range [0,1], so to achieve an
430N/A // x/y offset of approximately one pixel we have to normalize
430N/A // to that range here
430N/A texW = srcOps->pResource->GetDesc()->Width;
430N/A texH = srcOps->pResource->GetDesc()->Height;
430N/A xoff = 1.0f / texW;
430N/A yoff = 1.0f / texH;
430N/A
430N/A if (edgeZeroFill) {
430N/A flags |= CONVOLVE_EDGE_ZERO_FILL;
430N/A }
430N/A if (kernelWidth == 5 && kernelHeight == 5) {
430N/A flags |= CONVOLVE_5X5;
430N/A }
430N/A
430N/A // locate/enable the shader program for the given flags
430N/A res = d3dc->EnableConvolveProgram(flags);
430N/A RETURN_STATUS_IF_FAILED(res);
430N/A
430N/A // update the "uniform" image min/max values
430N/A // (texcoords are in the range [0,1])
430N/A // imgEdge[0] = imgMin.x
430N/A // imgEdge[1] = imgMin.y
430N/A // imgEdge[2] = imgMax.x
430N/A // imgEdge[3] = imgMax.y
430N/A edgeX = (kernelWidth/2) * xoff;
430N/A edgeY = (kernelHeight/2) * yoff;
430N/A imgEdge[0] = edgeX;
430N/A imgEdge[1] = edgeY;
430N/A imgEdge[2] = (((jfloat)srcOps->width) / texW) - edgeX;
430N/A imgEdge[3] = (((jfloat)srcOps->height) / texH) - edgeY;
430N/A pd3dDevice = d3dc->Get3DDevice();
430N/A pd3dDevice->SetPixelShaderConstantF(0, imgEdge, 1);
430N/A
430N/A // update the "uniform" kernel offsets and values
430N/A kIndex = 0;
430N/A for (i = -kernelHeight/2; i < kernelHeight/2+1; i++) {
430N/A for (j = -kernelWidth/2; j < kernelWidth/2+1; j++) {
430N/A kernelVals[kIndex+0] = j*xoff;
430N/A kernelVals[kIndex+1] = i*yoff;
430N/A kernelVals[kIndex+2] = NEXT_FLOAT(kernel);
430N/A kernelVals[kIndex+3] = 0.0f; // unused
430N/A kIndex += 4;
430N/A }
430N/A }
430N/A return pd3dDevice->SetPixelShaderConstantF(1, kernelVals, kernelSize);
430N/A}
430N/A
430N/AHRESULT
430N/AD3DBufImgOps_DisableConvolveOp(D3DContext *d3dc)
430N/A{
430N/A IDirect3DDevice9 *pd3dDevice;
430N/A
430N/A J2dTraceLn(J2D_TRACE_INFO, "D3DBufImgOps_DisableConvolveOp");
430N/A
430N/A RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
430N/A d3dc->UpdateState(STATE_CHANGE);
430N/A
430N/A // disable the ConvolveOp shader
430N/A pd3dDevice = d3dc->Get3DDevice();
430N/A return pd3dDevice->SetPixelShader(NULL);
430N/A}
430N/A
430N/A/**************************** RescaleOp support *****************************/
430N/A
430N/AHRESULT
430N/AD3DBufImgOps_EnableRescaleOp(D3DContext *d3dc,
430N/A jboolean nonPremult,
430N/A unsigned char *scaleFactors,
430N/A unsigned char *offsets)
430N/A{
430N/A HRESULT res;
430N/A IDirect3DDevice9 *pd3dDevice;
430N/A jint flags = 0;
430N/A
430N/A J2dTraceLn(J2D_TRACE_INFO, "D3DBufImgOps_EnableRescaleOp");
430N/A
430N/A RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
430N/A
430N/A d3dc->UpdateState(STATE_CHANGE);
430N/A
430N/A // choose the appropriate shader, depending on the source image
430N/A if (nonPremult) {
430N/A flags |= RESCALE_NON_PREMULT;
430N/A }
430N/A
430N/A // locate/enable the shader program for the given flags
430N/A res = d3dc->EnableRescaleProgram(flags);
430N/A RETURN_STATUS_IF_FAILED(res);
430N/A
430N/A // update the "uniform" scale factor values (note that the Java-level
430N/A // dispatching code always passes down 4 values here, regardless of
430N/A // the original source image type)
430N/A pd3dDevice = d3dc->Get3DDevice();
430N/A pd3dDevice->SetPixelShaderConstantF(0, (float *)scaleFactors, 1);
430N/A
430N/A // update the "uniform" offset values (note that the Java-level
430N/A // dispatching code always passes down 4 values here, and that the
430N/A // offsets will have already been normalized to the range [0,1])
430N/A return pd3dDevice->SetPixelShaderConstantF(1, (float *)offsets, 1);
430N/A}
430N/A
430N/AHRESULT
430N/AD3DBufImgOps_DisableRescaleOp(D3DContext *d3dc)
430N/A{
430N/A IDirect3DDevice9 *pd3dDevice;
430N/A
430N/A J2dTraceLn(J2D_TRACE_INFO, "D3DBufImgOps_DisableRescaleOp");
430N/A
430N/A RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
430N/A
430N/A d3dc->UpdateState(STATE_CHANGE);
430N/A
430N/A // disable the RescaleOp shader
430N/A pd3dDevice = d3dc->Get3DDevice();
430N/A return pd3dDevice->SetPixelShader(NULL);
430N/A}
430N/A
430N/A/**************************** LookupOp support ******************************/
430N/A
430N/AHRESULT
430N/AD3DBufImgOps_EnableLookupOp(D3DContext *d3dc,
430N/A jboolean nonPremult, jboolean shortData,
430N/A jint numBands, jint bandLength, jint offset,
430N/A void *tableValues)
430N/A{
430N/A HRESULT res;
430N/A IDirect3DDevice9 *pd3dDevice;
430N/A D3DResource *pLutTexRes;
430N/A IDirect3DTexture9 *pLutTex;
430N/A int bytesPerElem = (shortData ? 2 : 1);
430N/A jfloat foffsets[4];
430N/A void *bands[4];
430N/A int i;
430N/A jint flags = 0;
430N/A
430N/A J2dTraceLn4(J2D_TRACE_INFO,
430N/A "D3DBufImgOps_EnableLookupOp: short=%d num=%d len=%d off=%d",
430N/A shortData, numBands, bandLength, offset);
430N/A
430N/A RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
430N/A
430N/A d3dc->UpdateState(STATE_CHANGE);
430N/A
430N/A // choose the appropriate shader, depending on the source image
430N/A // and the number of bands involved
430N/A if (numBands != 4) {
430N/A flags |= LOOKUP_USE_SRC_ALPHA;
430N/A }
430N/A if (nonPremult) {
430N/A flags |= LOOKUP_NON_PREMULT;
430N/A }
430N/A
430N/A // locate/enable the shader program for the given flags
430N/A res = d3dc->EnableLookupProgram(flags);
430N/A RETURN_STATUS_IF_FAILED(res);
430N/A
430N/A // update the "uniform" offset value
430N/A for (i = 0; i < 4; i++) {
430N/A foffsets[i] = offset / 255.0f;
430N/A }
430N/A pd3dDevice = d3dc->Get3DDevice();
430N/A pd3dDevice->SetPixelShaderConstantF(0, foffsets, 1);
430N/A
430N/A res = d3dc->GetResourceManager()->GetLookupOpLutTexture(&pLutTexRes);
430N/A RETURN_STATUS_IF_FAILED(res);
430N/A pLutTex = pLutTexRes->GetTexture();
430N/A
430N/A // update the lookup table with the user-provided values
430N/A if (numBands == 1) {
430N/A // replicate the single band for R/G/B; alpha band is unused
430N/A for (i = 0; i < 3; i++) {
430N/A bands[i] = tableValues;
430N/A }
430N/A bands[3] = NULL;
430N/A } else if (numBands == 3) {
430N/A // user supplied band for each of R/G/B; alpha band is unused
430N/A for (i = 0; i < 3; i++) {
430N/A bands[i] = PtrAddBytes(tableValues, i*bandLength*bytesPerElem);
430N/A }
430N/A bands[3] = NULL;
430N/A } else if (numBands == 4) {
430N/A // user supplied band for each of R/G/B/A
430N/A for (i = 0; i < 4; i++) {
430N/A bands[i] = PtrAddBytes(tableValues, i*bandLength*bytesPerElem);
430N/A }
430N/A }
430N/A
430N/A // upload the bands one row at a time into our lookup table texture
430N/A D3DLOCKED_RECT lockedRect;
430N/A res = pLutTex->LockRect(0, &lockedRect, NULL, D3DLOCK_NOSYSLOCK);
430N/A RETURN_STATUS_IF_FAILED(res);
430N/A
430N/A jushort *pBase = (jushort*)lockedRect.pBits;
430N/A for (i = 0; i < 4; i++) {
430N/A jushort *pDst;
430N/A if (bands[i] == NULL) {
430N/A continue;
430N/A }
430N/A pDst = pBase + (i * 256);
430N/A if (shortData) {
430N/A memcpy(pDst, bands[i], bandLength*sizeof(jushort));
430N/A } else {
430N/A int j;
430N/A jubyte *pSrc = (jubyte *)bands[i];
430N/A for (j = 0; j < bandLength; j++) {
430N/A pDst[j] = (jushort)(pSrc[j] << 8);
430N/A }
430N/A }
430N/A }
430N/A pLutTex->UnlockRect(0);
430N/A
430N/A // bind the lookup table to texture unit 1 and enable texturing
430N/A res = d3dc->SetTexture(pLutTex, 1);
430N/A pd3dDevice->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
430N/A pd3dDevice->SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
430N/A pd3dDevice->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
430N/A pd3dDevice->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
430N/A return res;
430N/A}
430N/A
430N/AHRESULT
430N/AD3DBufImgOps_DisableLookupOp(D3DContext *d3dc)
430N/A{
430N/A IDirect3DDevice9 *pd3dDevice;
430N/A
430N/A J2dTraceLn(J2D_TRACE_INFO, "D3DBufImgOps_DisableLookupOp");
430N/A
430N/A RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
430N/A
430N/A d3dc->UpdateState(STATE_CHANGE);
430N/A
430N/A // disable the LookupOp shader
430N/A pd3dDevice = d3dc->Get3DDevice();
430N/A pd3dDevice->SetPixelShader(NULL);
430N/A
430N/A // disable the lookup table on texture unit 1
430N/A return d3dc->SetTexture(NULL, 1);
430N/A}