blob: 980f62b8164aa33d09481d01d091755a993c6b1c [file] [log] [blame]
/*
* Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
#include <malloc.h>
#include "sun_java2d_d3d_D3DTextRenderer.h"
#include "SurfaceData.h"
#include "Region.h"
#include "glyphblitting.h"
#include "fontscalerdefs.h"
#include "AccelGlyphCache.h"
#include "j2d_md.h"
#include "jlong.h"
#include "ddrawUtils.h"
#include "D3DContext.h"
#include "D3DUtils.h"
#include "Win32SurfaceData.h"
extern "C" {
#define MAX_STATIC_QUADS_NUM 40
static int indicesInited = 0;
static short vertexIndices[MAX_STATIC_QUADS_NUM*6];
static J2DLV_QUAD vertexQuads[MAX_STATIC_QUADS_NUM];
/**
* Initializes the array of index vertices used for rendering
* glyphs using cached texture.
*/
static void
InitIndexArray()
{
int ii, vi;
memset(vertexQuads, 0, sizeof(vertexQuads));
for (ii = 0, vi = 0; ii < MAX_STATIC_QUADS_NUM*6; ii += 6, vi += 4) {
vertexIndices[ii + 0] = vi + 0;
vertexIndices[ii + 1] = vi + 1;
vertexIndices[ii + 2] = vi + 2;
vertexIndices[ii + 3] = vi + 0;
vertexIndices[ii + 4] = vi + 2;
vertexIndices[ii + 5] = vi + 3;
}
}
/**
* Renders each glyph directly from the glyph texture cache.
*/
static HRESULT
D3DDrawGlyphList_UseCache(JNIEnv *env, Win32SDOps *wsdo,
D3DContext *d3dc,
ImageRef *glyphs, jint totalGlyphs)
{
int glyphCounter;
HRESULT res = DDERR_GENERIC;
DXSurface *glyphCacheTexture;
J2dTraceLn(J2D_TRACE_INFO, "D3DDrawGlyphList_UseCache");
int color = d3dc->colorPixel;
int quadCounter = 0;
DDrawSurface *ddTargetSurface = d3dc->GetTargetSurface();
if (ddTargetSurface == NULL) {
return DDERR_GENERIC;
}
ddTargetSurface->GetExclusiveAccess();
d3dc->GetExclusiveAccess();
glyphCacheTexture = d3dc->GetGlyphCacheTexture();
IDirect3DDevice7 *d3dDevice = d3dc->Get3DDevice();
if (d3dDevice == NULL ||
FAILED(res = d3dc->BeginScene(STATE_MASKOP)))
{
d3dc->ReleaseExclusiveAccess();
ddTargetSurface->ReleaseExclusiveAccess();
return res;
}
if (FAILED(res = d3dc->SetTexture(glyphCacheTexture))) {
d3dc->EndScene(res);
d3dc->ReleaseExclusiveAccess();
ddTargetSurface->ReleaseExclusiveAccess();
return res;
}
if (!indicesInited) {
InitIndexArray();
indicesInited = 1;
}
for (glyphCounter = 0; (glyphCounter < totalGlyphs) && SUCCEEDED(res);
glyphCounter++)
{
// render glyph cached in texture object
const jubyte *pixels = (const jubyte *)glyphs[glyphCounter].pixels;
GlyphInfo *ginfo = (GlyphInfo *)glyphs[glyphCounter].glyphInfo;
CacheCellInfo *cell;
float x1, y1, x2, y2;
float tx1, ty1, tx2, ty2;
J2DLV_QUAD *quad;
// it the glyph is an empty space, skip it
if (!pixels) {
continue;
}
if (ginfo->cellInfo == NULL ||
// REMIND: this is a temp fix to allow a glyph be cached
// in caches for different devices.
// REMIND: check if this is even a problem: we're using
// managed textures, they may be automatically accelerated
// on a different device.
// If the glyph is cached on a different device, cache
// it on this context's device.
// This may result in thrashing if the same glyphs
// get rendered on different devices.
// Note: this is not thread-safe: we may change the coordinates
// while another thread is using this cell.
// A proper fix would allow a glyph to be cached in multiple
// caches at the same time.
d3dc->GetGlyphCache() != ginfo->cellInfo->cacheInfo)
{
// attempt to add glyph to accelerated glyph cache
if (FAILED(d3dc->GlyphCacheAdd(env, ginfo)) ||
ginfo->cellInfo == NULL)
{
continue;
}
}
cell = ginfo->cellInfo;
cell->timesRendered++;
x1 = (float)glyphs[glyphCounter].x;
y1 = (float)glyphs[glyphCounter].y;
x2 = x1 + (float)glyphs[glyphCounter].width;
y2 = y1 + (float)glyphs[glyphCounter].height;
tx1 = cell->tx1;
ty1 = cell->ty1;
tx2 = cell->tx2;
ty2 = cell->ty2;
quad = &vertexQuads[quadCounter++];
D3DU_INIT_VERTEX_QUAD(*quad, x1, y1, x2, y2, color ,
tx1, ty1, tx2, ty2);
if (quadCounter == MAX_STATIC_QUADS_NUM &&
SUCCEEDED(res = ddTargetSurface->IsLost()))
{
res = d3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
D3DFVF_J2DLVERTEX,
vertexQuads,
4*quadCounter,
(LPWORD)vertexIndices,
6*quadCounter, 0);
quadCounter = 0;
}
}
if (quadCounter > 0 && SUCCEEDED(res)) {
res = d3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
D3DFVF_J2DLVERTEX,
vertexQuads,
4*quadCounter,
(LPWORD)vertexIndices,
6*quadCounter, 0);
}
d3dc->EndScene(res);
d3dc->ReleaseExclusiveAccess();
ddTargetSurface->ReleaseExclusiveAccess();
return res;
}
static HRESULT
D3DDrawGlyphList_NoCache(JNIEnv *env, Win32SDOps *wsdo,
D3DContext *d3dc,
ImageRef *glyphs, jint totalGlyphs)
{
int glyphCounter;
float tx1, ty1, tx2, ty2;
jint tw, th;
DXSurface *maskTexture;
static J2DLVERTEX quadVerts[4] = {
{ 0.0f, 0.0f, 0.0f, 0x0, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0x0, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0x0, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0x0, 0.0f, 0.0f }
};
J2dTraceLn(J2D_TRACE_INFO, "D3DDrawGlyphList_NoCache");
DDrawSurface *ddTargetSurface = d3dc->GetTargetSurface();
if (ddTargetSurface == NULL) {
return DDERR_GENERIC;
}
ddTargetSurface->GetExclusiveAccess();
d3dc->GetExclusiveAccess();
HRESULT res = DDERR_GENERIC;
IDirect3DDevice7 *d3dDevice = d3dc->Get3DDevice();
if (d3dDevice == NULL) {
d3dc->ReleaseExclusiveAccess();
ddTargetSurface->ReleaseExclusiveAccess();
return res;
}
maskTexture = d3dc->GetMaskTexture();
if (maskTexture == NULL ||
FAILED(res = d3dc->BeginScene(STATE_MASKOP)))
{
d3dc->ReleaseExclusiveAccess();
ddTargetSurface->ReleaseExclusiveAccess();
return DDERR_GENERIC;
}
if (FAILED(res = d3dc->SetTexture(maskTexture))) {
d3dc->EndScene(res);
d3dc->ReleaseExclusiveAccess();
ddTargetSurface->ReleaseExclusiveAccess();
return res;
}
tx1 = 0.0f;
ty1 = 0.0f;
tw = D3DSD_MASK_TILE_SIZE;
th = D3DSD_MASK_TILE_SIZE;
D3DU_INIT_VERTEX_QUAD_COLOR(quadVerts, d3dc->colorPixel);
for (glyphCounter = 0; (glyphCounter < totalGlyphs) && SUCCEEDED(res);
glyphCounter++)
{
// render system memory glyph image
jint sx, sy, sw, sh;
jint x, y, w, h, x0;
const jubyte *pixels = (const jubyte *)glyphs[glyphCounter].pixels;
if (!pixels) {
continue;
}
x = glyphs[glyphCounter].x;
y = glyphs[glyphCounter].y;
w = glyphs[glyphCounter].width;
h = glyphs[glyphCounter].height;
x0 = x;
for (sy = 0; sy < h; sy += th, y += th) {
x = x0;
sh = ((sy + th) > h) ? (h - sy) : th;
for (sx = 0; sx < w; sx += tw, x += tw) {
sw = ((sx + tw) > w) ? (w - sx) : tw;
if (FAILED(d3dc->UploadImageToTexture(maskTexture,
(jubyte*)pixels,
0, 0, sx, sy,
sw, sh, w)))
{
continue;
}
// update the lower right texture coordinates
tx2 = ((float)sw) / tw;
ty2 = ((float)sh) / th;
D3DU_INIT_VERTEX_QUAD_XYUV(quadVerts,
(float)x, (float)y,
(float)(x+sw), (float)(y+sh),
tx1, ty1, tx2, ty2);
if (SUCCEEDED(res = ddTargetSurface->IsLost())) {
res = d3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN,
D3DFVF_J2DLVERTEX,
quadVerts, 4, 0);
}
}
}
}
d3dc->EndScene(res);
d3dc->ReleaseExclusiveAccess();
ddTargetSurface->ReleaseExclusiveAccess();
return res;
}
JNIEXPORT void JNICALL
D3DDrawGlyphList(JNIEnv *env, jobject d3dtr,
jlong pData, jlong pCtx,
ImageRef *glyphs, jint totalGlyphs,
jboolean useCache)
{
Win32SDOps *wsdo = (Win32SDOps *)jlong_to_ptr(pData);
D3DContext *d3dc = (D3DContext *)jlong_to_ptr(pCtx);
HRESULT res;
// Note: uncomment to control glyph caching via env. variable.
// useCache = useCache && !getenv("J2D_D3D_NOGLYPHCACHING");
if (d3dc == NULL) {
return;
}
if (useCache && SUCCEEDED(res = d3dc->InitGlyphCache())) {
D3D_EXEC_PRIM_LOOP(env, res, wsdo,
D3DDrawGlyphList_UseCache(env, wsdo, d3dc, glyphs,
totalGlyphs));
return;
}
D3D_EXEC_PRIM_LOOP(env, res, wsdo,
D3DDrawGlyphList_NoCache(env, wsdo, d3dc, glyphs,
totalGlyphs));
}
}