1 /*
2  * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 #include <jlong.h>
27 
28 #include "D3DBufImgOps.h"
29 #include "D3DContext.h"
30 #include "D3DRenderQueue.h"
31 #include "D3DSurfaceData.h"
32 #include "GraphicsPrimitiveMgr.h"
33 
34 /**************************** ConvolveOp support ****************************/
35 
36 /**
37  * The maximum kernel size supported by the ConvolveOp shader.
38  */
39 #define MAX_KERNEL_SIZE 25
40 
41 HRESULT
D3DBufImgOps_EnableConvolveOp(D3DContext * d3dc,jlong pSrcOps,jboolean edgeZeroFill,jint kernelWidth,jint kernelHeight,unsigned char * kernel)42 D3DBufImgOps_EnableConvolveOp(D3DContext *d3dc, jlong pSrcOps,
43                               jboolean edgeZeroFill,
44                               jint kernelWidth, jint kernelHeight,
45                               unsigned char *kernel)
46 {
47     HRESULT res;
48     IDirect3DDevice9 *pd3dDevice;
49     D3DSDOps *srcOps = (D3DSDOps *)jlong_to_ptr(pSrcOps);
50     jint kernelSize = kernelWidth * kernelHeight;
51     jint texW, texH;
52     jfloat xoff, yoff;
53     jfloat edgeX, edgeY;
54     jfloat imgEdge[4];
55     jfloat kernelVals[MAX_KERNEL_SIZE*4];
56     jint i, j, kIndex;
57     jint flags = 0;
58 
59     J2dTraceLn2(J2D_TRACE_INFO,
60                 "D3DBufImgOps_EnableConvolveOp: kernelW=%d kernelH=%d",
61                 kernelWidth, kernelHeight);
62 
63     RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
64     RETURN_STATUS_IF_NULL(srcOps, E_FAIL);
65 
66     d3dc->UpdateState(STATE_CHANGE);
67 
68     // texcoords are specified in the range [0,1], so to achieve an
69     // x/y offset of approximately one pixel we have to normalize
70     // to that range here
71     texW = srcOps->pResource->GetDesc()->Width;
72     texH = srcOps->pResource->GetDesc()->Height;
73     xoff = 1.0f / texW;
74     yoff = 1.0f / texH;
75 
76     if (edgeZeroFill) {
77         flags |= CONVOLVE_EDGE_ZERO_FILL;
78     }
79     if (kernelWidth == 5 && kernelHeight == 5) {
80         flags |= CONVOLVE_5X5;
81     }
82 
83     // locate/enable the shader program for the given flags
84     res = d3dc->EnableConvolveProgram(flags);
85     RETURN_STATUS_IF_FAILED(res);
86 
87     // update the "uniform" image min/max values
88     // (texcoords are in the range [0,1])
89     //   imgEdge[0] = imgMin.x
90     //   imgEdge[1] = imgMin.y
91     //   imgEdge[2] = imgMax.x
92     //   imgEdge[3] = imgMax.y
93     edgeX = (kernelWidth/2) * xoff;
94     edgeY = (kernelHeight/2) * yoff;
95     imgEdge[0] = edgeX;
96     imgEdge[1] = edgeY;
97     imgEdge[2] = (((jfloat)srcOps->width)  / texW) - edgeX;
98     imgEdge[3] = (((jfloat)srcOps->height) / texH) - edgeY;
99     pd3dDevice = d3dc->Get3DDevice();
100     pd3dDevice->SetPixelShaderConstantF(0, imgEdge, 1);
101 
102     // update the "uniform" kernel offsets and values
103     kIndex = 0;
104     for (i = -kernelHeight/2; i < kernelHeight/2+1; i++) {
105         for (j = -kernelWidth/2; j < kernelWidth/2+1; j++) {
106             kernelVals[kIndex+0] = j*xoff;
107             kernelVals[kIndex+1] = i*yoff;
108             kernelVals[kIndex+2] = NEXT_FLOAT(kernel);
109             kernelVals[kIndex+3] = 0.0f; // unused
110             kIndex += 4;
111         }
112     }
113     return pd3dDevice->SetPixelShaderConstantF(1, kernelVals, kernelSize);
114 }
115 
116 HRESULT
D3DBufImgOps_DisableConvolveOp(D3DContext * d3dc)117 D3DBufImgOps_DisableConvolveOp(D3DContext *d3dc)
118 {
119     IDirect3DDevice9 *pd3dDevice;
120 
121     J2dTraceLn(J2D_TRACE_INFO, "D3DBufImgOps_DisableConvolveOp");
122 
123     RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
124     d3dc->UpdateState(STATE_CHANGE);
125 
126     // disable the ConvolveOp shader
127     pd3dDevice = d3dc->Get3DDevice();
128     return pd3dDevice->SetPixelShader(NULL);
129 }
130 
131 /**************************** RescaleOp support *****************************/
132 
133 HRESULT
D3DBufImgOps_EnableRescaleOp(D3DContext * d3dc,jboolean nonPremult,unsigned char * scaleFactors,unsigned char * offsets)134 D3DBufImgOps_EnableRescaleOp(D3DContext *d3dc,
135                              jboolean nonPremult,
136                              unsigned char *scaleFactors,
137                              unsigned char *offsets)
138 {
139     HRESULT res;
140     IDirect3DDevice9 *pd3dDevice;
141     jint flags = 0;
142 
143     J2dTraceLn(J2D_TRACE_INFO, "D3DBufImgOps_EnableRescaleOp");
144 
145     RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
146 
147     d3dc->UpdateState(STATE_CHANGE);
148 
149     // choose the appropriate shader, depending on the source image
150     if (nonPremult) {
151         flags |= RESCALE_NON_PREMULT;
152     }
153 
154     // locate/enable the shader program for the given flags
155     res = d3dc->EnableRescaleProgram(flags);
156     RETURN_STATUS_IF_FAILED(res);
157 
158     // update the "uniform" scale factor values (note that the Java-level
159     // dispatching code always passes down 4 values here, regardless of
160     // the original source image type)
161     pd3dDevice = d3dc->Get3DDevice();
162     pd3dDevice->SetPixelShaderConstantF(0, (float *)scaleFactors, 1);
163 
164     // update the "uniform" offset values (note that the Java-level
165     // dispatching code always passes down 4 values here, and that the
166     // offsets will have already been normalized to the range [0,1])
167     return pd3dDevice->SetPixelShaderConstantF(1, (float *)offsets, 1);
168 }
169 
170 HRESULT
D3DBufImgOps_DisableRescaleOp(D3DContext * d3dc)171 D3DBufImgOps_DisableRescaleOp(D3DContext *d3dc)
172 {
173     IDirect3DDevice9 *pd3dDevice;
174 
175     J2dTraceLn(J2D_TRACE_INFO, "D3DBufImgOps_DisableRescaleOp");
176 
177     RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
178 
179     d3dc->UpdateState(STATE_CHANGE);
180 
181     // disable the RescaleOp shader
182     pd3dDevice = d3dc->Get3DDevice();
183     return pd3dDevice->SetPixelShader(NULL);
184 }
185 
186 /**************************** LookupOp support ******************************/
187 
188 HRESULT
D3DBufImgOps_EnableLookupOp(D3DContext * d3dc,jboolean nonPremult,jboolean shortData,jint numBands,jint bandLength,jint offset,void * tableValues)189 D3DBufImgOps_EnableLookupOp(D3DContext *d3dc,
190                             jboolean nonPremult, jboolean shortData,
191                             jint numBands, jint bandLength, jint offset,
192                             void *tableValues)
193 {
194     HRESULT res;
195     IDirect3DDevice9 *pd3dDevice;
196     D3DResource *pLutTexRes;
197     IDirect3DTexture9 *pLutTex;
198     int bytesPerElem = (shortData ? 2 : 1);
199     jfloat foffsets[4];
200     void *bands[4];
201     int i;
202     jint flags = 0;
203 
204     for (i = 0; i < 4; i++) {
205         bands[i] = NULL;
206     }
207     J2dTraceLn4(J2D_TRACE_INFO,
208                 "D3DBufImgOps_EnableLookupOp: short=%d num=%d len=%d off=%d",
209                 shortData, numBands, bandLength, offset);
210 
211     RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
212 
213     d3dc->UpdateState(STATE_CHANGE);
214 
215     // choose the appropriate shader, depending on the source image
216     // and the number of bands involved
217     if (numBands != 4) {
218         flags |= LOOKUP_USE_SRC_ALPHA;
219     }
220     if (nonPremult) {
221         flags |= LOOKUP_NON_PREMULT;
222     }
223 
224     // locate/enable the shader program for the given flags
225     res = d3dc->EnableLookupProgram(flags);
226     RETURN_STATUS_IF_FAILED(res);
227 
228     // update the "uniform" offset value
229     for (i = 0; i < 4; i++) {
230         foffsets[i] = offset / 255.0f;
231     }
232     pd3dDevice = d3dc->Get3DDevice();
233     pd3dDevice->SetPixelShaderConstantF(0, foffsets, 1);
234 
235     res = d3dc->GetResourceManager()->GetLookupOpLutTexture(&pLutTexRes);
236     RETURN_STATUS_IF_FAILED(res);
237     pLutTex = pLutTexRes->GetTexture();
238 
239     // update the lookup table with the user-provided values
240     if (numBands == 1) {
241         // replicate the single band for R/G/B; alpha band is unused
242         for (i = 0; i < 3; i++) {
243             bands[i] = tableValues;
244         }
245         bands[3] = NULL;
246     } else if (numBands == 3) {
247         // user supplied band for each of R/G/B; alpha band is unused
248         for (i = 0; i < 3; i++) {
249             bands[i] = PtrAddBytes(tableValues, i*bandLength*bytesPerElem);
250         }
251         bands[3] = NULL;
252     } else if (numBands == 4) {
253         // user supplied band for each of R/G/B/A
254         for (i = 0; i < 4; i++) {
255             bands[i] = PtrAddBytes(tableValues, i*bandLength*bytesPerElem);
256         }
257     }
258 
259     // upload the bands one row at a time into our lookup table texture
260     D3DLOCKED_RECT lockedRect;
261     res = pLutTex->LockRect(0, &lockedRect, NULL, D3DLOCK_NOSYSLOCK);
262     RETURN_STATUS_IF_FAILED(res);
263 
264     jushort *pBase = (jushort*)lockedRect.pBits;
265     for (i = 0; i < 4; i++) {
266         jushort *pDst;
267         if (bands[i] == NULL) {
268             continue;
269         }
270         pDst = pBase + (i * 256);
271         if (shortData) {
272             memcpy(pDst, bands[i], bandLength*sizeof(jushort));
273         } else {
274             int j;
275             jubyte *pSrc = (jubyte *)bands[i];
276             for (j = 0; j < bandLength; j++) {
277                 pDst[j] = (jushort)(pSrc[j] << 8);
278             }
279         }
280     }
281     pLutTex->UnlockRect(0);
282 
283     // bind the lookup table to texture unit 1 and enable texturing
284     res = d3dc->SetTexture(pLutTex, 1);
285     pd3dDevice->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
286     pd3dDevice->SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
287     pd3dDevice->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
288     pd3dDevice->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
289     return res;
290 }
291 
292 HRESULT
D3DBufImgOps_DisableLookupOp(D3DContext * d3dc)293 D3DBufImgOps_DisableLookupOp(D3DContext *d3dc)
294 {
295     IDirect3DDevice9 *pd3dDevice;
296 
297     J2dTraceLn(J2D_TRACE_INFO, "D3DBufImgOps_DisableLookupOp");
298 
299     RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
300 
301     d3dc->UpdateState(STATE_CHANGE);
302 
303     // disable the LookupOp shader
304     pd3dDevice = d3dc->Get3DDevice();
305     pd3dDevice->SetPixelShader(NULL);
306 
307     // disable the lookup table on texture unit 1
308     return d3dc->SetTexture(NULL, 1);
309 }
310