/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "D3DPipeline.h"
#include "jlong.h"
#include "GraphicsPrimitiveMgr.h"
#include "D3DContext.h"
#include "D3DSurfaceData.h"
#include "D3DBufImgOps.h"
#include "D3DPaints.h"
#include "D3DRenderQueue.h"
#include "D3DShaders.h"
#include "D3DTextRenderer.h"
#include "D3DPipelineManager.h"
#include "D3DGlyphCache.h"
typedef struct {
} D3DBlendRule;
/**
* This table contains the standard blending rules (or Porter-Duff compositing
* factors) used in SetRenderState(), indexed by the rule constants from the
* AlphaComposite class.
*/
};
void
{
ZeroMemory(m, sizeof(D3DMATRIX));
m->_33 = 0.5f;
m->_44 = 1.0f;
m->_41 = -1.0f;
m->_42 = 1.0f;
m->_43 = 0.5f;
}
void
{
}
// the following methods are copies of the AffineTransform's class
// corresponding methods, with these changes to the indexes:
// 00 -> 11
// 11 -> 22
// 01 -> 21
// 10 -> 12
// 02 -> 41
// 12 -> 42
void
{
}
#ifdef UPDATE_TX
void
{
}
void
{
float det;
return;
}
}
void
{
}
void
{
float x = *px;
float y = *py;
}
void
{
x -= m->_41;
y -= m->_42;
*px = 0.0f;
*py = 0.0f;
} else {
}
}
#endif // UPDATE_TX
static void
{
}
// static
{
delete *ppCtx;
}
return res;
}
{
pd3dObject = pd3d;
pd3dDevice = NULL;
pResourceMgr = NULL;
pMaskCache = NULL;
pSyncQuery = NULL;
pSyncRTRes = NULL;
pStateBlock = NULL;
extraAlpha = 1.0f;
}
{
EndScene();
}
if (pMaskCache != NULL) {
}
if (pLCDGlyphCache != NULL) {
}
if (pGrayscaleGlyphCache != NULL) {
}
if (pResourceMgr != NULL) {
if (pSyncRTRes != NULL) {
pSyncRTRes = NULL;
}
}
}
{
"D3DContext::ReleaseContextResources: pd3dDevice = 0x%x",
// dispose shader lists
}
D3DContext::~D3DContext() {
"~D3DContext: pd3dDevice=0x%x, pd3dObject =0x%x",
}
{
"D3DContext::InitDevice: device %d", adapterOrdinal);
// disable some of the unneeded and costly d3d functionality
// set the default texture addressing mode
// REMIND: check supported filters with
// IDirect3D9::CheckDeviceFormat with D3DUSAGE_QUERY_FILTER
// these states never change
// init the array of latest textures
if (pResourceMgr == NULL) {
} else {
}
} else {
}
if (pMaskCache == NULL) {
} else{
}
if (pLCDGlyphCache != NULL) {
// we can live without the cache
}
}
if (pGrayscaleGlyphCache != NULL) {
// we can live without the cache
}
}
if (pSyncQuery == NULL) {
// this is allowed to fail, do not propagate the error
"D3DContext::InitDevice: sync query not available");
pSyncQuery = NULL;
}
}
if (pSyncRTRes == NULL) {
if (FAILED(GetResourceManager()->
"D3DContext::InitDevice: "
"error creating sync surface");
}
}
"D3DContext::InitDefice: successfully initialized device %d",
return res;
}
{
if (pd3dDevice != NULL) {
if (res == D3DERR_DEVICELOST) {
// nothing to be done here, wait for D3DERR_DEVICENOTRESET
return res;
} else if (res == D3DERR_DEVICENOTRESET) {
res = ResetContext();
} else {
// some unexpected error
"unknown error %x from TestCooperativeLevel");
}
} else {
}
} else {
}
return res;
}
{
if (pd3dDevice != NULL) {
// reset to the current display mode if we're windowed,
// otherwise to the display mode we were in when the device
// was lost
newParams.BackBufferWidth = 0;
}
}
return res;
}
{
// this is needed so that we can find the stencil buffer format
}
// do not set device window in the windowed mode, we use additional
// swap chains for rendering, the default chain is not used. otherwise
// our scratch focus window will be made visible
if (pNewParams->Windowed) {
}
// mode. It may either be set to the default focus window (when there are
// no more devices in fs mode), or to fs window for another device
// in fs mode. See D3DPipelineManager::GetCurrentFocusWindow.
if (pd3dDevice != NULL) {
" focus window changed, need to recreate the device");
// if fs -> windowed, first exit fs, then recreate, otherwise
// the screen might be left in a different display mode
" exiting full-screen mode, reset the device");
"cound not reset the device");
}
}
// note that here we should release all device resources, not only
// thos in the default pool since the device is released
}
}
if (pd3dDevice != NULL) {
{
}
"D3DContext::ConfigureContext: cound not reset the device");
return res;
}
"D3DContext::ConfigureContext: successfully reset device: %d",
} else {
{
"D3DContext::ConfigureContext: failed to get caps");
return res;
}
{
}
// not preserving fpu control word could cause issues (4860749)
"[V] dwBehaviorFlags=D3DCREATE_FPU_PRESERVE|");
"D3DCREATE_HARDWARE_VERTEXPROCESSING");
} else {
"D3DCREATE_SOFTWARE_VERTEXPROCESSING");
}
// Handling focus changes by ourselves proved to be problematic,
// so we're reverting back to D3D handling
// dwBehaviorFlags |= D3DCREATE_NOWINDOWCHANGES;
pNewParams, &pd3dDevice)))
{
"D3DContext::ConfigureContext: error creating d3d device");
return res;
}
"D3DContext::ConfigureContext: successfully created device: %d",
}
curParams = *pNewParams;
// during the creation of the device d3d modifies this field, we reset
// it back to 0
return res;
}
res = InitContextCaps();
return res;
}
{
params.hDeviceWindow = 0;
return ConfigureContext(¶ms);
}
{
if (pSyncQuery != NULL) {
while (S_FALSE ==
}
if (pSyncRTRes != NULL) {
pSurface->UnlockRect();
}
}
return res;
}
{
if (pStateBlock != NULL) {
"D3DContext::SaveState: existing state block!");
}
{
} else {
"D3DContext::SaveState: failed to create state block");
}
return res;
}
{
if (pStateBlock != NULL) {
} else {
"D3DContext::RestoreState: failed to restore state");
}
} else {
"D3DContext::RestoreState: empty state block!");
}
return res;
}
{
if (fType == D3DTEXF_POINT) {
}
if (fType == D3DTEXF_LINEAR) {
}
return FALSE;
}
{
if (fType == D3DTEXF_POINT) {
}
if (fType == D3DTEXF_LINEAR) {
}
return FALSE;
}
{
format);
}
{
return
descStencil.Format)));
}
" current stencil buffer is not compatible with new Render Target");
return false;
}
{
return res;
}
}
return res;
}
{
"D3DContext::SetRenderTarget: pSurface=0x%x",
pSurface);
if (pCurrentTarget != pSurface) {
"error setting render target");
return res;
}
if (!IsDepthStencilBufferOk(&descNew)) {
return res;
}
}
}
}
// we set the transform even if the render target didn't change;
// this is because in some cases (fs mode) we use the default SwapChain of
// the device, and its render target will be the same as the device's, and
// we have to set the matrix correctly. This shouldn't be a performance
// issue as render target changes are relatively rare
return res;
}
{
if (pd3dDevice == NULL) {
return E_FAIL;
}
// no need for state change, just flush the queue
}
return res;
}
{
if (pd3dDevice == NULL) {
return E_FAIL;
}
// no need for state change, just flush the queue
// In order to correctly map texels to pixels we need to
// adjust geometry by -0.5f in the transformed space.
// In order to do that we first create a translated matrix
// and then concatenate it with the world transform.
//
// Note that we only use non-id transform with DrawTexture,
// the rest is rendered pre-transformed.
//
// The identity transform for textures is handled in
// D3DVertexCacher::DrawTexture() because shifting by -0.5 for id
// transform breaks lines rendering.
}
return res;
}
{
" x1=%-4d y1=%-4d x2=%-4d y2=%-4d",
// no need for state change, just flush the queue
{
" disabling clip (== render target dimensions)");
}
// clip to the dimensions of the target surface, otherwise
// SetScissorRect will fail
} else {
" x1=%-4d y1=%-4d x2=%-4d y2=%-4d",
}
return res;
}
{
// no need for state change, just flush the queue
}
{
// REMIND: this method could be optimized: we could keep the
// every time.
if (stEnabled) {
return CLIP_RECT;
}
if (zEnabled) {
return CLIP_SHAPE;
}
return CLIP_NONE;
}
/**
* This method assumes that ::SetRenderTarget has already
* been called. SetRenderTarget creates and attaches a
* depth buffer to the target surface prior to setting it
* as target surface to the device.
*/
{
// save alpha blending state
// translate the clip spans by 1.0f in z direction so that the
// clip spans are rendered to the z buffer
// The depth buffer is first cleared with zeroes, which is the farthest
// plane from the viewer (our projection matrix is an inversed orthogonal
// transform).
// To set the clip we'll render the clip spans with Z coordinates of 1.0f
// (the closest to the viewer). Since all rendering primitives
// have their vertices' Z coordinate set to 0.0, they will effectively be
// clipped because the Z depth test for them will fail (vertex with 1.0
// depth is closer than the one with 0.0f)
//res = BeginScene(STATE_SHAPE_CLIPOP);
return res;
}
{
// no need for state change, just flush the queue
res = FlushVertexQueue();
// restore alpha blending state
// resore the transform
// Enable the depth buffer.
// We disable further updates to the depth buffer: it should only
// be updated in SetClip method.
return res;
}
{
#ifndef PtrAddBytes
#endif // PtrAddBytes
// these are only counted for LCD glyph uploads
" rect={%-4d, %-4d, %-4d, %-4d}",
// it is safe to lock with discard because we don't care about the
// contents of dynamic textures and dstx,dsty for this case is
// always 0,0 because we are uploading into a tile texture
}
"D3DContext::UploadImageToTexture: could "\
"not lock texture");
return res;
}
if (srcFormat == TILEFMT_1BYTE_ALPHA) {
// either a MaskFill tile, or a grayscale glyph
do {
} while (--srcHeight > 0);
}
// only need to set the alpha channel (the D3D texture
// state will be setup in this case to replicate the
// alpha channel as needed)
}
}
}
} else if (srcFormat == TILEFMT_3BYTE_RGB) {
// LCD glyph with RGB order
// alpha channel is ignored in this case
// (note that this is backwards from what one might
// expect; it appears that D3DFMT_R8G8B8 is actually
// laid out in BGR order in memory)
}
}
}
// alpha channel is ignored in this case
}
}
}
} else if (srcFormat == TILEFMT_3BYTE_BGR) {
// LCD glyph with BGR order
do {
// alpha channel is ignored in this case
// (note that this is backwards from what one might
// expect; it appears that D3DFMT_R8G8B8 is actually
// laid out in BGR order in memory)
} while (--srcHeight > 0);
}
// alpha channel is ignored in this case
}
}
}
} else if (srcFormat == TILEFMT_4BYTE_ARGB_PRE) {
// MaskBlit tile
do {
} while (--srcHeight > 0);
}
} else {
// should not happen, no-op just in case...
}
if (pPixelsTouchedL) {
}
if (pPixelsTouchedR) {
}
return pTexture->UnlockRect(0);
}
{
if (pLCDGlyphCache == NULL) {
}
return S_OK;
}
{
if (pGrayscaleGlyphCache == NULL) {
}
return S_OK;
}
{
extraAlpha = 1.0f;
return res;
}
{
"D3DContext::SetAlphaComposite: rule=%-1d ea=%f flags=%d",
// we can safely disable blending when:
// - comp is SrcNoEa or SrcOverNoEa, and
// - the source is opaque
// (turning off blending can have a large positive impact on performance)
(ea == 1.0f) &&
(flags & D3DC_SRC_IS_OPAQUE))
{
" disabling alpha comp rule=%-1d ea=1.0 src=opq)", rule);
} else {
}
extraAlpha = ea;
return res;
}
#ifdef UPDATE_TX
// Note: this method of adjusting pixel to texel mapping proved to be
// difficult to perfect. The current variation works great for id,
// scale (including all kinds of flips) transforms, but not still not
// for generic transforms.
//
// Since we currently only do DrawTexture with non-id transform we instead
// adjust the geometry (see D3DVertexCacher::DrawTexture(), SetTransform())
//
// In order to enable this code path UpdateTextureTransforms needs to
// be called in SetTexture(), SetTransform() and ResetTranform().
{
if (dwSamplerToUpdate == -1) {
// update all used samplers, dwMaxSampler will be set to max
dwSampler = 0;
"updating all samplers");
} else {
// update only given sampler, dwMaxSampler will be set to it as well
"updating sampler %d", dwSampler);
}
do {
J2dTraceLn4(10,
J2dTraceLn4(10,
J2dTraceLn4(10,
J2dTraceLn4(10,
// this formula works for scales and flips
}
}
// shift by .5 texel, but take into account
// the scale factor of the device transform
// REMIND: this approach is not entirely correct,
// as it only takes into account the scale of the device
// transform.
} else {
}
dwSampler++;
} while (dwSampler <= dwMaxSampler);
return res;
}
#endif // UPDATE_TX
/**
* We go into the pains of maintaining the list of set textures
* instead of just calling GetTexture() and comparing the old one
* with the new one because it's actually noticeably slower to call
* GetTexture() (note that we'd have to then call Release() on the
* texture since GetTexture() increases texture's ref. count).
*/
{
"D3DContext::SetTexture: incorrect sampler: %d", dwSampler);
return E_FAIL;
}
return res;
}
// REMIND: see comment at UpdateTextureTransforms
#ifdef UPDATE_TX
#endif
} else {
}
}
return res;
}
{
}
return res;
}
HRESULT /*NOLOCK*/
{
// The op is the same as last time, so we can return immediately.
return res;
} else if (opState != STATE_CHANGE) {
res = FlushVertexQueue();
}
switch (opState) {
case STATE_MASKOP:
pMaskCache->Disable();
break;
case STATE_GLYPHOP:
break;
case STATE_TEXTUREOP:
// optimization: certain state changes (those marked STATE_CHANGE)
// are allowed while texturing is enabled.
// In this case, we can allow previousOp to remain as it is and
// then return early.
if (newState == STATE_CHANGE) {
return res;
}
// REMIND: not necessary if we are switching to MASKOP or GLYPHOP
// (or a complex paint, for that matter), but would that be a
// worthwhile optimization?
break;
case STATE_AAPGRAMOP:
break;
default:
break;
}
switch (newState) {
case STATE_MASKOP:
pMaskCache->Enable();
break;
case STATE_GLYPHOP:
D3DTR_EnableGlyphVertexCache(this);
break;
case STATE_TEXTUREOP:
break;
case STATE_AAPGRAMOP:
break;
default:
break;
}
return res;
}
{
}
return E_FAIL;
}
{
if (!pd3dDevice) {
return E_FAIL;
} else {
if (!bBeginScenePending) {
// this will cause context reinitialization
}
return res;
}
return S_OK;
}
}
if (bBeginScenePending) {
return pd3dDevice->EndScene();
}
return S_OK;
}
/**
* Compiles and links the given fragment shader program. If
* successful, this function returns a handle to the newly created shader
* program; otherwise returns 0.
*/
{
"D3DContext::CreateFragmentProgram: flags=%d",
flags);
"D3DContext::CreateFragmentProgram: error creating program");
return NULL;
}
// add it to the cache
return pProgram;
}
/**
* Locates and enables a fragment program given a list of shader programs
* (ShaderInfos), using this context's state and flags as search
* parameters. The "flags" parameter is a bitwise-or'd value that helps
* differentiate one program for another; the interpretation of this value
* varies depending on the type of shader (BufImgOp, Paint, etc) but here
* it is only used to find another ShaderInfo with that same "flags" value.
*/
{
return E_FAIL;
}
}
"D3DContext::EnableFragmentProgram: error setting pixel shader");
return res;
}
return S_OK;
}
{
}
{
}
{
}
{
}
{
&rescalePrograms, flags);
}
{
&lookupPrograms, flags);
}
{
if (lcdTextProgram == NULL) {
&lcdTextProgram)))
{
return res;
}
}
"D3DContext::EnableLCDTextProgram: error setting pixel shader");
return res;
}
return S_OK;
}
{
if (aaPgramProgram == NULL) {
&aaPgramProgram))) {
"error creating pixel shader");
return res;
}
}
"error setting pixel shader");
return res;
}
return S_OK;
}
{
if (aaPgramProgram != NULL) {
"D3DContext::DisableAAParallelogramProgram: "
"error clearing pixel shader");
return res;
}
}
return S_OK;
}
{
}
{
}
{
}
return E_FAIL;
}
if (IsAlphaRTSurfaceSupported()) {
}
if (IsAlphaRTTSupported()) {
}
if (IsOpaqueRTTSupported()) {
}
if (IsPixelShader20Supported()) {
" | CAPS_LCD_SHADER | CAPS_BIOP_SHADER | CAPS_PS20");
// Pre-PS3.0 video boards are very slow with the AA shader, so
// we will require PS30 hw even though the shader is compiled for 2.0a
// if (IsGradientInstructionExtensionSupported()) {
// contextCaps |= CAPS_AA_SHADER;
// J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_AA_SHADER");
// }
}
if (IsPixelShader30Supported()) {
if ((contextCaps & CAPS_AA_SHADER) == 0) {
// This flag was not already mentioned above...
}
}
if (IsMultiTexturingSupported()) {
}
if (!IsPow2TexturesOnly()) {
}
if (!IsSquareTexturesOnly()) {
}
return S_OK;
}