WinUAE/od-win32/direct3d.cpp

4278 lines
124 KiB
C++

#include <windows.h>
#include "resource.h"
#include "sysconfig.h"
#include "sysdeps.h"
#if defined (D3D) && defined (GFXFILTER)
#define D3DXFX_LARGEADDRESS_HANDLE
#ifdef D3DXFX_LARGEADDRESS_HANDLE
#define EFFECTCOMPILERFLAGS D3DXFX_LARGEADDRESSAWARE
#else
#define EFFECTCOMPILERFLAGS 0
#endif
#define EFFECT_VERSION 3
#define D3DX9DLL _T("d3dx9_43.dll")
#define TWOPASS 1
#define SHADER 1
#include "options.h"
#include "xwin.h"
#include "custom.h"
#include "drawing.h"
#include "dxwrap.h"
#include "win32.h"
#include "win32gfx.h"
#include "gfxfilter.h"
#include "statusline.h"
#include "hq2x_d3d.h"
#include "zfile.h"
#include "uae.h"
#include "gui.h"
#include "threaddep\thread.h"
extern int D3DEX, shaderon, d3ddebug;
int forcedframelatency = -1;
#include <d3d9.h>
#include <d3dx9.h>
#include "direct3d.h"
static TCHAR *D3DHEAD = _T("-");
static bool showoverlay = true;
static int slicecnt;
static int clearcnt;
static bool debugcolors;
static bool noclear;
static bool cannoclear;
int fakemodewaitms;
static int leds[LED_MAX];
static const TCHAR *overlayleds[] = {
_T("power"),
_T("df0"),
_T("df1"),
_T("df2"),
_T("df3"),
_T("hd"),
_T("cd"),
_T("md"),
_T("net"),
NULL
};
static const int ledtypes[] = {
LED_POWER,
LED_DF0,
LED_DF1,
LED_DF2,
LED_DF3,
LED_HD,
LED_CD,
LED_MD,
LED_NET
};
#define MAX_PASSES 2
#define SHADERTYPE_BEFORE 1
#define SHADERTYPE_AFTER 2
#define SHADERTYPE_MIDDLE 3
#define SHADERTYPE_MASK_BEFORE 4
#define SHADERTYPE_MASK_AFTER 5
#define SHADERTYPE_MASK_MIDDLE 6
#define SHADERTYPE_POST 10
struct shaderdata
{
int type;
int psPreProcess;
int worktex_width;
int worktex_height;
int targettex_width;
int targettex_height;
LPDIRECT3DTEXTURE9 lpWorkTexture1;
LPDIRECT3DTEXTURE9 lpWorkTexture2;
LPDIRECT3DTEXTURE9 lpTempTexture;
LPDIRECT3DVOLUMETEXTURE9 lpHq2xLookupTexture;
LPD3DXEFFECT pEffect;
// Technique stuff
D3DXHANDLE m_PreprocessTechnique1EffectHandle;
D3DXHANDLE m_PreprocessTechnique2EffectHandle;
D3DXHANDLE m_CombineTechniqueEffectHandle;
// Matrix Handles
D3DXHANDLE m_MatWorldEffectHandle;
D3DXHANDLE m_MatViewEffectHandle;
D3DXHANDLE m_MatProjEffectHandle;
D3DXHANDLE m_MatWorldViewEffectHandle;
D3DXHANDLE m_MatViewProjEffectHandle;
D3DXHANDLE m_MatWorldViewProjEffectHandle;
// Texture Handles
D3DXHANDLE m_SourceDimsEffectHandle;
D3DXHANDLE m_InputDimsEffectHandle;
D3DXHANDLE m_TargetDimsEffectHandle;
D3DXHANDLE m_TexelSizeEffectHandle;
D3DXHANDLE m_ScaleEffectHandle;
D3DXHANDLE m_SourceTextureEffectHandle;
D3DXHANDLE m_WorkingTexture1EffectHandle;
D3DXHANDLE m_WorkingTexture2EffectHandle;
D3DXHANDLE m_Hq2xLookupTextureHandle;
// Masks
LPDIRECT3DTEXTURE9 masktexture;
int masktexture_w, masktexture_h;
// Stuff
D3DXHANDLE framecounterHandle;
};
struct d3d9overlay
{
struct d3d9overlay *next;
int id;
int x, y;
LPDIRECT3DTEXTURE9 tex;
};
#define MAX_SHADERS (2 * MAX_FILTERSHADERS + 2)
#define SHADER_POST 0
struct d3dstruct
{
int psEnabled, psActive;
struct shaderdata shaders[MAX_SHADERS];
LPDIRECT3DTEXTURE9 lpPostTempTexture;
IDirect3DSurface9 *screenshotsurface;
D3DFORMAT tformat;
int d3d_enabled, d3d_ex;
IDirect3D9 *d3d;
IDirect3D9Ex *d3dex;
IDirect3DSwapChain9 *d3dswapchain;
D3DPRESENT_PARAMETERS dpp;
D3DDISPLAYMODEEX modeex;
IDirect3DDevice9 *d3ddev;
IDirect3DDevice9Ex *d3ddevex;
D3DSURFACE_DESC dsdbb;
LPDIRECT3DTEXTURE9 texture, sltexture, ledtexture, blanktexture;
LPDIRECT3DTEXTURE9 mask2texture, mask2textureleds[9], mask2textureled_power_dim;
int mask2textureledoffsets[9 * 2];
IDirect3DQuery9 *query;
float mask2texture_w, mask2texture_h, mask2texture_ww, mask2texture_wh;
float mask2texture_wwx, mask2texture_hhx, mask2texture_minusx, mask2texture_minusy;
float mask2texture_multx, mask2texture_multy, mask2texture_offsetw;
LPDIRECT3DTEXTURE9 cursorsurfaced3d;
struct d3d9overlay *extoverlays;
IDirect3DVertexBuffer9 *vertexBuffer;
ID3DXSprite *sprite;
HWND d3dhwnd;
int devicelost;
int locked, fulllocked;
int cursor_offset_x, cursor_offset_y, cursor_offset2_x, cursor_offset2_y;
float maskmult_x, maskmult_y;
RECT mask2rect;
bool wasstilldrawing_broken;
bool renderdisabled;
HANDLE filenotificationhandle;
int frames_since_init;
volatile bool fakemode;
uae_u8 *fakebitmap;
uae_thread_id fakemodetid;
D3DXMATRIXA16 m_matProj, m_matProj2, m_matProj_out;
D3DXMATRIXA16 m_matWorld, m_matWorld2, m_matWorld_out;
D3DXMATRIXA16 m_matView, m_matView2, m_matView_out;
D3DXMATRIXA16 m_matPreProj;
D3DXMATRIXA16 m_matPreView;
D3DXMATRIXA16 m_matPreWorld;
D3DXMATRIXA16 postproj;
D3DXVECTOR4 maskmult, maskshift;
D3DXVECTOR4 fakesize;
int ledwidth, ledheight;
int max_texture_w, max_texture_h;
int tin_w, tin_h, tout_w, tout_h, window_h, window_w;
int t_depth, dmult, dmultxh, dmultxv;
int required_sl_texture_w, required_sl_texture_h;
int vsync2, guimode, maxscanline, variablerefresh;
int resetcount;
double cursor_x, cursor_y;
bool cursor_v, cursor_scale;
int statusbar_vx, statusbar_hx;
struct gfx_filterdata *filterd3d;
int filterd3didx;
int scanline_osl1, scanline_osl2, scanline_osl3, scanline_osl4;
D3DXHANDLE postSourceTextureHandle;
D3DXHANDLE postMaskTextureHandle;
D3DXHANDLE postTechnique, postTechniquePlain, postTechniqueAlpha;
D3DXHANDLE postMatrixSource;
D3DXHANDLE postMaskMult, postMaskShift;
D3DXHANDLE postFilterMode;
D3DXHANDLE postTexelSize;
D3DXHANDLE postFramecounterHandle;
float m_scale;
LPCSTR m_strName;
int ddraw_fs;
int ddraw_fs_attempt;
LPDIRECTDRAW7 ddraw;
};
static struct d3dstruct d3ddata[MAX_AMIGAMONITORS];
#define NUMVERTICES 8
#define D3DFVF_TLVERTEX D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1
struct TLVERTEX {
D3DXVECTOR3 position; // vertex position
D3DCOLOR diffuse;
D3DXVECTOR2 texcoord; // texture coords
};
static void ddraw_fs_hack_free (struct d3dstruct *d3d)
{
HRESULT hr;
if (!d3d->ddraw_fs)
return;
if (d3d->ddraw_fs == 2)
d3d->ddraw->RestoreDisplayMode ();
hr = d3d->ddraw->SetCooperativeLevel (d3d->d3dhwnd, DDSCL_NORMAL);
if (FAILED (hr)) {
write_log (_T("IDirectDraw7_SetCooperativeLevel CLEAR: %s\n"), DXError (hr));
}
d3d->ddraw->Release ();
d3d->ddraw = NULL;
d3d->ddraw_fs = 0;
}
static int ddraw_fs_hack_init (struct d3dstruct *d3d)
{
HRESULT hr;
struct MultiDisplay *md;
ddraw_fs_hack_free(d3d);
DirectDraw_get_GUIDs();
md = getdisplay(&currprefs, 0);
if (!md)
return 0;
hr = DirectDrawCreateEx(md->primary ? NULL : &md->ddguid, (LPVOID*)&d3d->ddraw, IID_IDirectDraw7, NULL);
if (FAILED (hr)) {
write_log (_T("DirectDrawCreateEx failed, %s\n"), DXError (hr));
return 0;
}
d3d->ddraw_fs = 1;
hr = d3d->ddraw->SetCooperativeLevel(d3d->d3dhwnd, DDSCL_ALLOWREBOOT | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
if (FAILED (hr)) {
write_log (_T("IDirectDraw7_SetCooperativeLevel SET: %s\n"), DXError (hr));
ddraw_fs_hack_free (d3d);
return 0;
}
hr = d3d->ddraw->SetDisplayMode(d3d->dpp.BackBufferWidth, d3d->dpp.BackBufferHeight, d3d->t_depth, d3d->dpp.FullScreen_RefreshRateInHz, 0);
if (FAILED (hr)) {
write_log (_T("1:IDirectDraw7_SetDisplayMode: %s\n"), DXError (hr));
if (d3d->dpp.FullScreen_RefreshRateInHz && isvsync_chipset () < 0) {
hr = d3d->ddraw->SetDisplayMode(d3d->dpp.BackBufferWidth, d3d->dpp.BackBufferHeight, d3d->t_depth, 0, 0);
if (FAILED (hr))
write_log (_T("2:IDirectDraw7_SetDisplayMode: %s\n"), DXError (hr));
}
if (FAILED (hr)) {
write_log (_T("IDirectDraw7_SetDisplayMode: %s\n"), DXError (hr));
ddraw_fs_hack_free(d3d);
return 0;
}
}
d3d->ddraw_fs = 2;
return 1;
}
static TCHAR *D3D_ErrorText (HRESULT error)
{
return _T("");
}
static TCHAR *D3D_ErrorString (HRESULT dival)
{
static TCHAR dierr[200];
_stprintf (dierr, _T("%08X S=%d F=%04X C=%04X (%d) (%s)"),
dival, (dival & 0x80000000) ? 1 : 0,
HRESULT_FACILITY(dival),
HRESULT_CODE(dival),
HRESULT_CODE(dival),
D3D_ErrorText (dival));
return dierr;
}
static D3DXMATRIX* MatrixOrthoOffCenterLH (D3DXMATRIXA16 *pOut, float l, float r, float b, float t, float zn, float zf)
{
pOut->_11=2.0f/r; pOut->_12=0.0f; pOut->_13=0.0f; pOut->_14=0.0f;
pOut->_21=0.0f; pOut->_22=2.0f/t; pOut->_23=0.0f; pOut->_24=0.0f;
pOut->_31=0.0f; pOut->_32=0.0f; pOut->_33=1.0f; pOut->_34=0.0f;
pOut->_41=-1.0f; pOut->_42=-1.0f; pOut->_43=0.0f; pOut->_44=1.0f;
return pOut;
}
static D3DXMATRIX* MatrixScaling (D3DXMATRIXA16 *pOut, float sx, float sy, float sz)
{
pOut->_11=sx; pOut->_12=0.0f; pOut->_13=0.0f; pOut->_14=0.0f;
pOut->_21=0.0f; pOut->_22=sy; pOut->_23=0.0f; pOut->_24=0.0f;
pOut->_31=0.0f; pOut->_32=0.0f; pOut->_33=sz; pOut->_34=0.0f;
pOut->_41=0.0f; pOut->_42=0.0f; pOut->_43=0.0f; pOut->_44=1.0f;
return pOut;
}
static D3DXMATRIX* MatrixTranslation (D3DXMATRIXA16 *pOut, float tx, float ty, float tz)
{
pOut->_11=1.0f; pOut->_12=0.0f; pOut->_13=0.0f; pOut->_14=0.0f;
pOut->_21=0.0f; pOut->_22=1.0f; pOut->_23=0.0f; pOut->_24=0.0f;
pOut->_31=0.0f; pOut->_32=0.0f; pOut->_33=1.0f; pOut->_34=0.0f;
pOut->_41=tx; pOut->_42=ty; pOut->_43=tz; pOut->_44=1.0f;
return pOut;
}
static TCHAR *D3DX_ErrorString (HRESULT hr, LPD3DXBUFFER Errors)
{
static TCHAR *buffer;
static int buffersize;
TCHAR *s = NULL;
int size = 0;
if (Errors)
s = au ((char*)Errors->GetBufferPointer ());
size = (s == NULL ? 0 : _tcslen (s)) + 1000;
if (size + 1000 > buffersize) {
xfree (buffer);
buffer = xmalloc (TCHAR, size);
buffersize = size;
}
buffer[0] = 0;
if (hr != S_OK)
_tcscpy (buffer, D3D_ErrorString (hr));
if (s) {
if (buffer[0])
_tcscat (buffer, _T(" "));
_tcscat (buffer, s);
}
xfree (s);
return buffer;
}
static int isd3d (struct d3dstruct *d3d)
{
if (d3d->fakemode || d3d->devicelost || !d3d->d3ddev || !d3d->d3d_enabled || d3d->renderdisabled)
return 0;
return 1;
}
static void waitfakemode (struct d3dstruct *d3d)
{
while (d3d->fakemode) {
sleep_millis (10);
}
}
enum psEffect_Pass { psEffect_None, psEffect_PreProcess1, psEffect_PreProcess2, psEffect_Combine };
static int postEffect_ParseParameters (struct d3dstruct *d3d, LPD3DXEFFECTCOMPILER EffectCompiler, LPD3DXEFFECT effect, struct shaderdata *s)
{
d3d->postSourceTextureHandle = effect->GetParameterByName (NULL, "SourceTexture");
d3d->postMaskTextureHandle = effect->GetParameterByName (NULL, "OverlayTexture");
d3d->postTechnique = effect->GetTechniqueByName ("PostTechnique");
d3d->postTechniquePlain = effect->GetTechniqueByName ("PostTechniquePlain");
d3d->postTechniqueAlpha = effect->GetTechniqueByName ("PostTechniqueAlpha");
d3d->postMatrixSource = effect->GetParameterByName (NULL, "mtx");
d3d->postMaskMult = effect->GetParameterByName (NULL, "maskmult");
d3d->postMaskShift = effect->GetParameterByName (NULL, "maskshift");
d3d->postFilterMode = effect->GetParameterByName (NULL, "filtermode");
d3d->postTexelSize = effect->GetParameterByName (NULL, "texelsize");
d3d->postFramecounterHandle = effect->GetParameterByName (NULL, "framecounter");
if (!d3d->postMaskShift || !d3d->postMaskMult || !d3d->postFilterMode || !d3d->postMatrixSource || !d3d->postTexelSize) {
gui_message (_T("Mismatched _winuae.fx! Exiting.."));
abort ();
}
return true;
}
static void postEffect_freeParameters(struct d3dstruct *d3d)
{
d3d->postSourceTextureHandle = NULL;
d3d->postMaskTextureHandle = NULL;
d3d->postTechnique = NULL;
d3d->postTechniquePlain = NULL;
d3d->postTechniqueAlpha = NULL;
d3d->postMatrixSource = NULL;
d3d->postMaskMult = NULL;
d3d->postMaskShift = NULL;
d3d->postFilterMode = NULL;
d3d->postTexelSize = NULL;
d3d->postFramecounterHandle = NULL;
}
static int psEffect_ParseParameters (struct d3dstruct *d3d, LPD3DXEFFECTCOMPILER EffectCompiler, LPD3DXEFFECT effect, D3DXEFFECT_DESC EffectDesc, struct shaderdata *s)
{
HRESULT hr = S_OK;
// Look at parameters for semantics and annotations that we know how to interpret
D3DXPARAMETER_DESC ParamDesc;
D3DXPARAMETER_DESC AnnotDesc;
D3DXHANDLE hParam;
D3DXHANDLE hAnnot;
LPDIRECT3DBASETEXTURE9 pTex = NULL;
UINT iParam, iAnnot;
if(effect == NULL)
return 0;
for(iParam = 0; iParam < EffectDesc.Parameters; iParam++) {
LPCSTR pstrName = NULL;
LPCSTR pstrFunction = NULL;
D3DXHANDLE pstrFunctionHandle = NULL;
LPCSTR pstrTarget = NULL;
LPCSTR pstrTextureType = NULL;
INT Width = D3DX_DEFAULT;
INT Height= D3DX_DEFAULT;
INT Depth = D3DX_DEFAULT;
hParam = effect->GetParameter (NULL, iParam);
hr = effect->GetParameterDesc (hParam, &ParamDesc);
if (FAILED (hr)) {
write_log (_T("GetParameterDescParm(%d) failed: %s\n"), D3DHEAD, iParam, D3DX_ErrorString (hr, NULL));
return 0;
}
s->framecounterHandle = effect->GetParameterByName (NULL, "framecounter");
hr = S_OK;
if(ParamDesc.Semantic != NULL) {
if(ParamDesc.Class == D3DXPC_MATRIX_ROWS || ParamDesc.Class == D3DXPC_MATRIX_COLUMNS) {
if(strcmpi(ParamDesc.Semantic, "world") == 0)
s->m_MatWorldEffectHandle = hParam;
else if(strcmpi(ParamDesc.Semantic, "view") == 0)
s->m_MatViewEffectHandle = hParam;
else if(strcmpi(ParamDesc.Semantic, "projection") == 0)
s->m_MatProjEffectHandle = hParam;
else if(strcmpi(ParamDesc.Semantic, "worldview") == 0)
s->m_MatWorldViewEffectHandle = hParam;
else if(strcmpi(ParamDesc.Semantic, "viewprojection") == 0)
s->m_MatViewProjEffectHandle = hParam;
else if(strcmpi(ParamDesc.Semantic, "worldviewprojection") == 0)
s->m_MatWorldViewProjEffectHandle = hParam;
} else if(ParamDesc.Class == D3DXPC_VECTOR && ParamDesc.Type == D3DXPT_FLOAT) {
if (strcmpi(ParamDesc.Semantic, "sourcedims") == 0)
s->m_SourceDimsEffectHandle = hParam;
if (strcmpi(ParamDesc.Semantic, "inputdims") == 0)
s->m_InputDimsEffectHandle = hParam;
if (strcmpi(ParamDesc.Semantic, "targetdims") == 0)
s->m_TargetDimsEffectHandle = hParam;
else if (strcmpi(ParamDesc.Semantic, "texelsize") == 0)
s->m_TexelSizeEffectHandle = hParam;
else if (strcmpi(ParamDesc.Semantic, "sourcescale") == 0)
s->m_ScaleEffectHandle = hParam;
} else if(ParamDesc.Class == D3DXPC_SCALAR && ParamDesc.Type == D3DXPT_FLOAT) {
if(strcmpi(ParamDesc.Semantic, "SCALING") == 0)
hr = effect->GetFloat(hParam, &d3d->m_scale);
} else if(ParamDesc.Class == D3DXPC_OBJECT && ParamDesc.Type == D3DXPT_TEXTURE) {
if(strcmpi(ParamDesc.Semantic, "SOURCETEXTURE") == 0)
s->m_SourceTextureEffectHandle = hParam;
if(strcmpi(ParamDesc.Semantic, "WORKINGTEXTURE") == 0)
s->m_WorkingTexture1EffectHandle = hParam;
if(strcmpi(ParamDesc.Semantic, "WORKINGTEXTURE1") == 0)
s->m_WorkingTexture2EffectHandle = hParam;
if(strcmpi(ParamDesc.Semantic, "HQ2XLOOKUPTEXTURE") == 0)
s->m_Hq2xLookupTextureHandle = hParam;
} else if(ParamDesc.Class == D3DXPC_OBJECT && ParamDesc.Type == D3DXPT_STRING) {
LPCSTR pstrTechnique = NULL;
if(strcmpi(ParamDesc.Semantic, "COMBINETECHNIQUE") == 0) {
hr = effect->GetString(hParam, &pstrTechnique);
s->m_CombineTechniqueEffectHandle = effect->GetTechniqueByName(pstrTechnique);
} else if(strcmpi(ParamDesc.Semantic, "PREPROCESSTECHNIQUE") == 0) {
hr = effect->GetString(hParam, &pstrTechnique);
s->m_PreprocessTechnique1EffectHandle = effect->GetTechniqueByName(pstrTechnique);
} else if(strcmpi(ParamDesc.Semantic, "PREPROCESSTECHNIQUE1") == 0) {
hr = effect->GetString(hParam, &pstrTechnique);
s->m_PreprocessTechnique2EffectHandle = effect->GetTechniqueByName(pstrTechnique);
} else if(strcmpi(ParamDesc.Semantic, "NAME") == 0) {
hr = effect->GetString(hParam, &d3d->m_strName);
}
}
if (FAILED (hr)) {
write_log (_T("ParamDesc.Semantic failed: %s\n"), D3DHEAD, D3DX_ErrorString (hr, NULL));
return 0;
}
}
for(iAnnot = 0; iAnnot < ParamDesc.Annotations; iAnnot++) {
hAnnot = effect->GetAnnotation (hParam, iAnnot);
hr = effect->GetParameterDesc(hAnnot, &AnnotDesc);
if (FAILED (hr)) {
write_log (_T("GetParameterDescAnnot(%d) failed: %s\n"), D3DHEAD, iAnnot, D3DX_ErrorString (hr, NULL));
return 0;
}
hr = S_OK;
if(strcmpi(AnnotDesc.Name, "name") == 0) {
hr = effect->GetString(hAnnot, &pstrName);
} else if(strcmpi(AnnotDesc.Name, "function") == 0) {
hr = effect->GetString(hAnnot, &pstrFunction);
pstrFunctionHandle = effect->GetFunctionByName(pstrFunction);
} else if(strcmpi(AnnotDesc.Name, "target") == 0) {
hr = effect->GetString(hAnnot, &pstrTarget);
} else if(strcmpi(AnnotDesc.Name, "width") == 0) {
hr = effect->GetInt(hAnnot, &Width);
} else if(strcmpi(AnnotDesc.Name, "height") == 0) {
hr = effect->GetInt(hAnnot, &Height);
} else if(strcmpi(AnnotDesc.Name, "depth") == 0) {
hr = effect->GetInt(hAnnot, &Depth);
} else if(strcmpi(AnnotDesc.Name, "type") == 0) {
hr = effect->GetString(hAnnot, &pstrTextureType);
}
if (FAILED (hr)) {
write_log (_T("GetString/GetInt(%d) failed: %s\n"), D3DHEAD, iAnnot, D3DX_ErrorString (hr, NULL));
return 0;
}
}
if(pstrFunctionHandle != NULL) {
LPD3DXBUFFER pTextureShader = NULL;
LPD3DXBUFFER lpErrors = 0;
if(pstrTarget == NULL || strcmp(pstrTarget,"tx_1_1"))
pstrTarget = "tx_1_0";
if(SUCCEEDED(hr = EffectCompiler->CompileShader(
pstrFunctionHandle, pstrTarget, D3DXSHADER_SKIPVALIDATION|D3DXSHADER_DEBUG, &pTextureShader, &lpErrors, NULL))) {
LPD3DXTEXTURESHADER ppTextureShader;
if (lpErrors)
lpErrors->Release ();
if(Width == D3DX_DEFAULT)
Width = 64;
if(Height == D3DX_DEFAULT)
Height = 64;
if(Depth == D3DX_DEFAULT)
Depth = 64;
D3DXCreateTextureShader((DWORD *)pTextureShader->GetBufferPointer(), &ppTextureShader);
if(pstrTextureType != NULL) {
if(strcmpi(pstrTextureType, "volume") == 0) {
LPDIRECT3DVOLUMETEXTURE9 pVolumeTex = NULL;
if(SUCCEEDED(hr = D3DXCreateVolumeTexture(d3d->d3ddev,
Width, Height, Depth, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pVolumeTex))) {
if(SUCCEEDED(hr = D3DXFillVolumeTextureTX(pVolumeTex, ppTextureShader))) {
pTex = pVolumeTex;
}
}
} else if(strcmpi(pstrTextureType, "cube") == 0) {
LPDIRECT3DCUBETEXTURE9 pCubeTex = NULL;
if(SUCCEEDED(hr = D3DXCreateCubeTexture(d3d->d3ddev,
Width, D3DX_DEFAULT, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pCubeTex))) {
if(SUCCEEDED(hr = D3DXFillCubeTextureTX(pCubeTex, ppTextureShader))) {
pTex = pCubeTex;
}
}
}
} else {
LPDIRECT3DTEXTURE9 p2DTex = NULL;
if(SUCCEEDED(hr = D3DXCreateTexture(d3d->d3ddev, Width, Height,
D3DX_DEFAULT, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &p2DTex))) {
if(SUCCEEDED(hr = D3DXFillTextureTX(p2DTex, ppTextureShader))) {
pTex = p2DTex;
}
}
}
effect->SetTexture(effect->GetParameter(NULL, iParam), pTex);
if (pTex)
pTex->Release ();
if (pTextureShader)
pTextureShader->Release ();
if (ppTextureShader)
ppTextureShader->Release ();
} else {
write_log (_T("%s: Could not compile texture shader: %s\n"), D3DHEAD, D3DX_ErrorString (hr, lpErrors));
if (lpErrors)
lpErrors->Release ();
return 0;
}
}
}
if (!s->m_CombineTechniqueEffectHandle && EffectDesc.Techniques > 0) {
s->m_CombineTechniqueEffectHandle = effect->GetTechnique(0);
}
return 1;
}
static int psEffect_hasPreProcess (struct shaderdata *s) { return s->m_PreprocessTechnique1EffectHandle != 0; }
static int psEffect_hasPreProcess2 (struct shaderdata *s) { return s->m_PreprocessTechnique2EffectHandle != 0; }
int xD3D_goodenough (void)
{
static int d3d_good;
LPDIRECT3D9 d3dx;
D3DCAPS9 d3dCaps;
if (d3d_good > 0)
return d3d_good;
if (d3d_good < 0)
return 0;
d3d_good = -1;
d3dx = Direct3DCreate9 (D3D_SDK_VERSION);
if (d3dx != NULL) {
if (SUCCEEDED (d3dx->GetDeviceCaps (D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps))) {
if (((d3dCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) == D3DPTEXTURECAPS_NONPOW2CONDITIONAL) || !(d3dCaps.TextureCaps & D3DPTEXTURECAPS_POW2)) {
if (!(d3dCaps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY) && (d3dCaps.Caps2 & D3DCAPS2_DYNAMICTEXTURES)) {
d3d_good = 1;
if (d3dCaps.PixelShaderVersion >= D3DPS_VERSION(1, 0)) {
d3d_good = 2;
if (shaderon < 0)
shaderon = 1;
}
}
}
}
d3dx->Release ();
}
#if SHADER == 0
shaderon = 0;
#endif
if (shaderon < 0)
shaderon = 0;
return d3d_good > 0 ? d3d_good : 0;
}
int xD3D_canshaders (void)
{
static int d3d_yesno = 0;
HMODULE h;
LPDIRECT3D9 d3dx;
D3DCAPS9 d3dCaps;
if (d3d_yesno < 0)
return 0;
if (d3d_yesno > 0)
return 1;
d3d_yesno = -1;
h = LoadLibrary (D3DX9DLL);
if (h != NULL) {
FreeLibrary (h);
d3dx = Direct3DCreate9 (D3D_SDK_VERSION);
if (d3dx != NULL) {
if (SUCCEEDED (d3dx->GetDeviceCaps (D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps))) {
if (d3dCaps.PixelShaderVersion >= D3DPS_VERSION(2,0)) {
write_log (_T("Direct3D: Pixel shader 2.0+ support detected, shader filters enabled.\n"));
d3d_yesno = 1;
}
}
d3dx->Release ();
}
}
return d3d_yesno > 0 ? 1 : 0;
}
static const char *fx10 = {
"// 3 (version)\n"
"//\n"
"// WinUAE Direct3D post processing shader\n"
"//\n"
"// by Toni Wilen 2012\n"
"\n"
"uniform extern float4x4 mtx;\n"
"uniform extern float2 maskmult;\n"
"uniform extern float2 maskshift;\n"
"uniform extern int filtermode;\n"
"uniform extern float2 texelsize;\n"
"\n"
"// final possibly filtered Amiga output\n"
"texture SourceTexture : SOURCETEXTURE;\n"
"\n"
"sampler SourceSampler = sampler_state {\n"
" Texture = (SourceTexture);\n"
" MinFilter = POINT;\n"
" MagFilter = POINT;\n"
" MipFilter = NONE;\n"
" AddressU = Clamp;\n"
" AddressV = Clamp;\n"
"};\n"
"\n"
"\n"
"texture OverlayTexture : OVERLAYTEXTURE;\n"
"\n"
"sampler OverlaySampler = sampler_state {\n"
" Texture = (OverlayTexture);\n"
" MinFilter = POINT;\n"
" MagFilter = POINT;\n"
" MipFilter = NONE;\n"
" AddressU = Wrap;\n"
" AddressV = Wrap;\n"
"};\n"
"\n"
"struct VS_OUTPUT_POST\n"
"{\n"
" float4 Position : POSITION;\n"
" float2 CentreUV : TEXCOORD0;\n"
" float2 Selector : TEXCOORD1;\n"
"};\n"
"\n"
"VS_OUTPUT_POST VS_Post(float3 pos : POSITION, float2 TexCoord : TEXCOORD0)\n"
"{\n"
" VS_OUTPUT_POST Out = (VS_OUTPUT_POST)0;\n"
"\n"
" Out.Position = mul(float4(pos, 1.0f), mtx);\n"
" Out.CentreUV = TexCoord;\n"
" Out.Selector = TexCoord * maskmult + maskshift;\n"
" return Out;\n"
"}\n"
"\n"
"float4 PS_Post(in VS_OUTPUT_POST inp) : COLOR\n"
"{\n"
" float4 s = tex2D(SourceSampler, inp.CentreUV);\n"
" float4 o = tex2D(OverlaySampler, inp.Selector);\n"
" return s * o;\n"
"}\n"
"\n"
"float4 PS_PostAlpha(in VS_OUTPUT_POST inp) : COLOR\n"
"{\n"
" float4 s = tex2D(SourceSampler, inp.CentreUV);\n"
" float4 o = tex2D(OverlaySampler, inp.Selector);\n"
" return s * (1 - o.a) + (o * o.a);\n"
"}\n"
"\n"
"float4 PS_PostPlain(in VS_OUTPUT_POST inp) : COLOR\n"
"{\n"
" float4 s = tex2D(SourceSampler, inp.CentreUV);\n"
" return s;\n"
"}\n"
"\n"
"// source and overlay texture\n"
"technique PostTechnique\n"
"{\n"
" pass P0\n"
" {\n"
" VertexShader = compile vs_1_0 VS_Post();\n"
" PixelShader = compile ps_1_0 PS_Post();\n"
" } \n"
"}\n"
"\n"
"// source and scanline texture with alpha\n"
"technique PostTechniqueAlpha\n"
"{\n"
" pass P0\n"
" {\n"
" VertexShader = compile vs_1_0 VS_Post();\n"
" PixelShader = compile ps_1_0 PS_PostAlpha();\n"
" } \n"
"}\n"
"\n"
"// only source texture\n"
"technique PostTechniquePlain\n"
"{\n"
" pass P0\n"
" {\n"
" VertexShader = compile vs_1_0 VS_Post();\n"
" PixelShader = compile ps_1_0 PS_PostPlain();\n"
" }\n"
"}\n"
};
static const char *fx20 = {
"// 3 (version)\n"
"//\n"
"// WinUAE Direct3D post processing shader\n"
"//\n"
"// by Toni Wilen 2012\n"
"\n"
"uniform extern float4x4 mtx;\n"
"uniform extern float2 maskmult;\n"
"uniform extern float2 maskshift;\n"
"uniform extern int filtermode;\n"
"uniform extern float2 texelsize;\n"
"\n"
"// final possibly filtered Amiga output\n"
"texture SourceTexture : SOURCETEXTURE;\n"
"\n"
"sampler SourceSampler = sampler_state {\n"
" Texture = (SourceTexture);\n"
" MinFilter = filtermode;\n"
" MagFilter = filtermode;\n"
" MipFilter = NONE;\n"
" AddressU = Clamp;\n"
" AddressV = Clamp;\n"
"};\n"
"\n"
"\n"
"texture OverlayTexture : OVERLAYTEXTURE;\n"
"\n"
"sampler OverlaySampler = sampler_state {\n"
" Texture = (OverlayTexture);\n"
" MinFilter = POINT;\n"
" MagFilter = POINT;\n"
" MipFilter = NONE;\n"
" AddressU = Wrap;\n"
" AddressV = Wrap;\n"
"};\n"
"\n"
"struct VS_OUTPUT_POST\n"
"{\n"
" float4 Position : POSITION;\n"
" float2 CentreUV : TEXCOORD0;\n"
" float2 Selector : TEXCOORD1;\n"
"};\n"
"\n"
"VS_OUTPUT_POST VS_Post(float3 pos : POSITION, float2 TexCoord : TEXCOORD0)\n"
"{\n"
" VS_OUTPUT_POST Out = (VS_OUTPUT_POST)0;\n"
"\n"
" Out.Position = mul(float4(pos, 1.0f), mtx);\n"
" Out.CentreUV = TexCoord;\n"
" Out.Selector = TexCoord * maskmult + maskshift;\n"
" return Out;\n"
"}\n"
"\n"
"float4 PS_Post(in VS_OUTPUT_POST inp) : COLOR\n"
"{\n"
" float4 s = tex2D(SourceSampler, inp.CentreUV);\n"
" float4 o = tex2D(OverlaySampler, inp.Selector);\n"
" return s * o;\n"
"}\n"
"\n"
"float4 PS_PostAlpha(in VS_OUTPUT_POST inp) : COLOR\n"
"{\n"
" float4 s = tex2D(SourceSampler, inp.CentreUV);\n"
" float4 o = tex2D(OverlaySampler, inp.Selector);\n"
" return s * (1 - o.a) + (o * o.a);\n"
"}\n"
"\n"
"float4 PS_PostPlain(in VS_OUTPUT_POST inp) : COLOR\n"
"{\n"
" float4 s = tex2D(SourceSampler, inp.CentreUV);\n"
" return s;\n"
"}\n"
"\n"
"// source and overlay texture\n"
"technique PostTechnique\n"
"{\n"
" pass P0\n"
" {\n"
" VertexShader = compile vs_1_0 VS_Post();\n"
" PixelShader = compile ps_2_0 PS_Post();\n"
" } \n"
"}\n"
"\n"
"// source and scanline texture with alpha\n"
"technique PostTechniqueAlpha\n"
"{\n"
" pass P0\n"
" {\n"
" VertexShader = compile vs_1_0 VS_Post();\n"
" PixelShader = compile ps_2_0 PS_PostAlpha();\n"
" } \n"
"}\n"
"\n"
"// only source texture\n"
"technique PostTechniquePlain\n"
"{\n"
" pass P0\n"
" {\n"
" VertexShader = compile vs_1_0 VS_Post();\n"
" PixelShader = compile ps_2_0 PS_PostPlain();\n"
" }\n"
"}\n"
};
static bool psEffect_LoadEffect (struct d3dstruct *d3d, const TCHAR *shaderfile, int full, struct shaderdata *s, int num)
{
int ret = 0;
LPD3DXEFFECTCOMPILER EffectCompiler = NULL;
LPD3DXBUFFER Errors = NULL;
LPD3DXBUFFER BufferEffect = NULL;
HRESULT hr;
TCHAR tmp[MAX_DPATH], tmp2[MAX_DPATH], tmp3[MAX_DPATH];
LPD3DXEFFECT effect = NULL;
static int first;
DWORD compileflags = d3d->psEnabled ? 0 : D3DXSHADER_USE_LEGACY_D3DX9_31_DLL;
int canusefile = 0, existsfile = 0;
bool plugin_path;
D3DXEFFECT_DESC EffectDesc;
compileflags |= EFFECTCOMPILERFLAGS;
plugin_path = get_plugin_path (tmp, sizeof tmp / sizeof (TCHAR), _T("filtershaders\\direct3d"));
_tcscpy (tmp3, tmp);
_tcscat (tmp, shaderfile);
if (!full) {
struct zfile *z = zfile_fopen (tmp, _T("r"));
if (z) {
existsfile = 1;
zfile_fgets (tmp2, sizeof tmp2 / sizeof (TCHAR), z);
zfile_fclose (z);
int ver = _tstol (tmp2 + 2);
if (ver == EFFECT_VERSION) {
canusefile = 1;
} else {
write_log (_T("'%s' mismatched version (%d != %d)\n"), tmp, ver, EFFECT_VERSION);
}
}
hr = E_FAIL;
if (canusefile) {
write_log (_T("%s: Attempting to load '%s'\n"), D3DHEAD, tmp);
hr = D3DXCreateEffectCompilerFromFile (tmp, NULL, NULL, compileflags, &EffectCompiler, &Errors);
if (FAILED (hr))
write_log (_T("%s: D3DXCreateEffectCompilerFromFile failed: %s\n"), D3DHEAD, D3DX_ErrorString (hr, Errors));
}
if (FAILED (hr)) {
const char *str = d3d->psEnabled ? fx20 : fx10;
int len = strlen (str);
if (!existsfile && plugin_path) {
struct zfile *z = zfile_fopen (tmp, _T("w"));
if (z) {
zfile_fwrite ((void*)str, len, 1, z);
zfile_fclose (z);
}
}
hr = D3DXCreateEffectCompiler (str, len, NULL, NULL, compileflags, &EffectCompiler, &Errors);
if (FAILED (hr)) {
write_log (_T("%s: D3DXCreateEffectCompiler failed: %s\n"), D3DHEAD, D3DX_ErrorString (hr, Errors));
goto end;
}
}
} else {
write_log (_T("%s: Attempting to load '%s'\n"), D3DHEAD, tmp);
hr = D3DXCreateEffectCompilerFromFile (tmp, NULL, NULL, compileflags, &EffectCompiler, &Errors);
if (FAILED (hr)) {
write_log (_T("%s: D3DXCreateEffectCompilerFromFile failed: %s\n"), D3DHEAD, D3DX_ErrorString (hr, Errors));
goto end;
}
}
if (Errors) {
write_log (_T("%s: '%s' warning: %s\n"), D3DHEAD, shaderfile, D3DX_ErrorString (hr, Errors));
Errors->Release();
Errors = NULL;
}
hr = EffectCompiler->CompileEffect (0, &BufferEffect, &Errors);
if (FAILED (hr)) {
write_log (_T("%s: CompileEffect failed: %s\n"), D3DHEAD, D3DX_ErrorString (hr, Errors));
goto end;
}
void *bp = BufferEffect->GetBufferPointer ();
int bplen = BufferEffect->GetBufferSize ();
hr = D3DXCreateEffect (d3d->d3ddev,
bp, bplen,
NULL, NULL,
EFFECTCOMPILERFLAGS,
NULL, &effect, &Errors);
if (FAILED (hr)) {
write_log (_T("%s: D3DXCreateEffect failed: %s\n"), D3DHEAD, D3DX_ErrorString (hr, Errors));
goto end;
}
hr = effect->GetDesc (&EffectDesc);
if (FAILED (hr)) {
write_log (_T("%s: effect->GetDesc() failed: %s\n"), D3DHEAD, D3DX_ErrorString (hr, Errors));
goto end;
}
if (full) {
if (!psEffect_ParseParameters (d3d, EffectCompiler, effect, EffectDesc, s))
goto end;
} else {
if (!postEffect_ParseParameters (d3d, EffectCompiler, effect, s))
goto end;
}
ret = 1;
d3d->frames_since_init = 0;
if (plugin_path && d3d->filenotificationhandle == NULL)
d3d->filenotificationhandle = FindFirstChangeNotification (tmp3, FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE);
end:
if (Errors)
Errors->Release ();
if (BufferEffect)
BufferEffect->Release ();
if (EffectCompiler)
EffectCompiler->Release ();
if (full) {
s->psPreProcess = FALSE;
if (ret) {
d3d->psActive = TRUE;
if (psEffect_hasPreProcess (s))
s->psPreProcess = TRUE;
}
}
if (ret)
write_log (_T("%s: pixelshader filter '%s':%d enabled\n"), D3DHEAD, tmp, num);
else
write_log (_T("%s: pixelshader filter '%s':%d failed to initialize\n"), D3DHEAD, tmp, num);
s->pEffect = effect;
return effect != NULL;
}
static int psEffect_SetMatrices (D3DXMATRIXA16 *matProj, D3DXMATRIXA16 *matView, D3DXMATRIXA16 *matWorld, struct shaderdata *s)
{
HRESULT hr;
if (s->m_MatWorldEffectHandle) {
hr = s->pEffect->SetMatrix (s->m_MatWorldEffectHandle, matWorld);
if (FAILED (hr)) {
write_log (_T("%s: Create:SetMatrix:matWorld %s\n"), D3DHEAD, D3D_ErrorString (hr));
return 0;
}
}
if (s->m_MatViewEffectHandle) {
hr = s->pEffect->SetMatrix (s->m_MatViewEffectHandle, matView);
if (FAILED (hr)) {
write_log (_T("%s: Create:SetMatrix:matView %s\n"), D3DHEAD, D3D_ErrorString (hr));
return 0;
}
}
if (s->m_MatProjEffectHandle) {
hr = s->pEffect->SetMatrix (s->m_MatProjEffectHandle, matProj);
if (FAILED (hr)) {
write_log (_T("%s: Create:SetMatrix:matProj %s\n"), D3DHEAD, D3D_ErrorString (hr));
return 0;
}
}
if (s->m_MatWorldViewEffectHandle) {
D3DXMATRIXA16 matWorldView;
D3DXMatrixMultiply (&matWorldView, matWorld, matView);
hr = s->pEffect->SetMatrix (s->m_MatWorldViewEffectHandle, &matWorldView);
if (FAILED (hr)) {
write_log (_T("%s: Create:SetMatrix:matWorldView %s\n"), D3DHEAD, D3D_ErrorString (hr));
return 0;
}
}
if (s->m_MatViewProjEffectHandle) {
D3DXMATRIXA16 matViewProj;
D3DXMatrixMultiply (&matViewProj, matView, matProj);
hr = s->pEffect->SetMatrix (s->m_MatViewProjEffectHandle, &matViewProj);
if (FAILED (hr)) {
write_log (_T("%s: Create:SetMatrix:matViewProj %s\n"), D3DHEAD, D3D_ErrorString (hr));
return 0;
}
}
if (s->m_MatWorldViewProjEffectHandle) {
D3DXMATRIXA16 tmp, matWorldViewProj;
D3DXMatrixMultiply (&tmp, matWorld, matView);
D3DXMatrixMultiply (&matWorldViewProj, &tmp, matProj);
hr = s->pEffect->SetMatrix (s->m_MatWorldViewProjEffectHandle, &matWorldViewProj);
if (FAILED (hr)) {
write_log (_T("%s: Create:SetMatrix:matWorldViewProj %s\n"), D3DHEAD, D3D_ErrorString (hr));
return 0;
}
}
return 1;
}
static int psEffect_SetTextures (LPDIRECT3DTEXTURE9 lpSource, struct shaderdata *s)
{
HRESULT hr;
D3DXVECTOR4 fDims, fTexelSize;
if (!s->m_SourceTextureEffectHandle) {
write_log (_T("%s: Texture with SOURCETEXTURE semantic not found\n"), D3DHEAD);
return 0;
}
hr = s->pEffect->SetTexture (s->m_SourceTextureEffectHandle, lpSource);
if (FAILED (hr)) {
write_log (_T("%s: SetTextures:lpSource %s\n"), D3DHEAD, D3D_ErrorString (hr));
return 0;
}
if (s->m_WorkingTexture1EffectHandle) {
hr = s->pEffect->SetTexture (s->m_WorkingTexture1EffectHandle, s->lpWorkTexture1);
if (FAILED (hr)) {
write_log (_T("%s: SetTextures:lpWorking1 %s\n"), D3DHEAD, D3D_ErrorString (hr));
return 0;
}
}
if (s->m_WorkingTexture2EffectHandle) {
hr = s->pEffect->SetTexture (s->m_WorkingTexture2EffectHandle, s->lpWorkTexture2);
if (FAILED (hr)) {
write_log (_T("%s: SetTextures:lpWorking2 %s\n"), D3DHEAD, D3D_ErrorString (hr));
return 0;
}
}
if (s->m_Hq2xLookupTextureHandle) {
hr = s->pEffect->SetTexture (s->m_Hq2xLookupTextureHandle, s->lpHq2xLookupTexture);
if (FAILED (hr)) {
write_log (_T("%s: SetTextures:lpHq2xLookupTexture %s\n"), D3DHEAD, D3D_ErrorString (hr));
return 0;
}
}
fDims.x = 256; fDims.y = 256; fDims.z = 1; fDims.w = 1;
fTexelSize.x = 1; fTexelSize.y = 1; fTexelSize.z = 1; fTexelSize.w = 1;
if (lpSource) {
D3DSURFACE_DESC Desc;
lpSource->GetLevelDesc (0, &Desc);
fDims.x = (FLOAT) Desc.Width;
fDims.y = (FLOAT) Desc.Height;
}
fTexelSize.x = 1.0f / fDims.x;
fTexelSize.y = 1.0f / fDims.y;
if (s->m_SourceDimsEffectHandle) {
hr = s->pEffect->SetVector(s->m_SourceDimsEffectHandle, &fDims);
if (FAILED(hr)) {
write_log(_T("%s: SetTextures:SetVector:Source %s\n"), D3DHEAD, D3D_ErrorString(hr));
return 0;
}
}
if (s->m_InputDimsEffectHandle) {
hr = s->pEffect->SetVector(s->m_InputDimsEffectHandle, &fDims);
if (FAILED(hr)) {
write_log(_T("%s: SetTextures:SetVector:Input %s\n"), D3DHEAD, D3D_ErrorString(hr));
return 0;
}
}
if (s->m_TargetDimsEffectHandle) {
D3DXVECTOR4 fDimsTarget;
fDimsTarget.x = s->targettex_width;
fDimsTarget.y = s->targettex_height;
fDimsTarget.z = 1;
fDimsTarget.w = 1;
hr = s->pEffect->SetVector(s->m_TargetDimsEffectHandle, &fDimsTarget);
if (FAILED(hr)) {
write_log(_T("%s: SetTextures:SetVector:Target %s\n"), D3DHEAD, D3D_ErrorString(hr));
return 0;
}
}
if (s->m_TexelSizeEffectHandle) {
hr = s->pEffect->SetVector (s->m_TexelSizeEffectHandle, &fTexelSize);
if (FAILED (hr)) {
write_log (_T("%s: SetTextures:SetVector:Texel %s\n"), D3DHEAD, D3D_ErrorString (hr));
return 0;
}
}
if (s->m_ScaleEffectHandle) {
D3DXVECTOR4 fScale;
fScale.x = 1 << currprefs.gfx_resolution;
fScale.y = 1 << currprefs.gfx_vresolution;
fScale.w = fScale.z = 1;
hr = s->pEffect->SetVector(s->m_ScaleEffectHandle, &fScale);
if (FAILED(hr)) {
write_log(_T("%s: SetTextures:SetVector:Scale %s\n"), D3DHEAD, D3D_ErrorString(hr));
return 0;
}
}
if (s->framecounterHandle)
s->pEffect->SetFloat(s->framecounterHandle, timeframes);
return 1;
}
static int psEffect_Begin (enum psEffect_Pass pass, UINT *pPasses, struct shaderdata *s)
{
HRESULT hr;
LPD3DXEFFECT effect = s->pEffect;
switch (pass)
{
case psEffect_PreProcess1:
hr = effect->SetTechnique (s->m_PreprocessTechnique1EffectHandle);
break;
case psEffect_PreProcess2:
hr = effect->SetTechnique (s->m_PreprocessTechnique2EffectHandle);
break;
case psEffect_Combine:
hr = effect->SetTechnique (s->m_CombineTechniqueEffectHandle);
break;
default:
hr = S_OK;
break;
}
if (FAILED (hr)) {
write_log (_T("%s: SetTechnique: %s\n"), D3DHEAD, D3D_ErrorString (hr));
return 0;
}
hr = effect->Begin (pPasses, 0);
if (FAILED (hr)) {
write_log (_T("%s: Begin: %s\n"), D3DHEAD, D3D_ErrorString (hr));
return 0;
}
return 1;
}
static int psEffect_BeginPass (LPD3DXEFFECT effect, UINT Pass)
{
HRESULT hr;
hr = effect->BeginPass (Pass);
if (FAILED (hr)) {
write_log (_T("%s: BeginPass: %s\n"), D3DHEAD, D3D_ErrorString (hr));
return 0;
}
return 1;
}
static int psEffect_EndPass (LPD3DXEFFECT effect)
{
HRESULT hr;
hr = effect->EndPass ();
if (FAILED (hr)) {
write_log (_T("%s: EndPass: %s\n"), D3DHEAD, D3D_ErrorString (hr));
return 0;
}
return 1;
}
static int psEffect_End (LPD3DXEFFECT effect)
{
HRESULT hr;
hr = effect->End ();
if (FAILED (hr)) {
write_log (_T("%s: End: %s\n"), D3DHEAD, D3D_ErrorString (hr));
return 0;
}
return 1;
}
static LPDIRECT3DTEXTURE9 createtext (struct d3dstruct *d3d, int w, int h, D3DFORMAT format)
{
LPDIRECT3DTEXTURE9 t;
D3DLOCKED_RECT locked;
HRESULT hr;
hr = d3d->d3ddev->CreateTexture (w, h, 1, D3DUSAGE_DYNAMIC, format, D3DPOOL_DEFAULT, &t, NULL);
if (FAILED (hr))
write_log (_T("%s: CreateTexture() D3DUSAGE_DYNAMIC failed: %s (%d*%d %08x)\n"),
D3DHEAD, D3D_ErrorString (hr), w, h, format);
if (FAILED (hr)) {
hr = d3d->d3ddev->CreateTexture (w, h, 1, 0, format, D3DPOOL_DEFAULT, &t, NULL);
}
if (FAILED (hr)) {
write_log (_T("%s: CreateTexture() failed: %s (%d*%d %08x)\n"),
D3DHEAD, D3D_ErrorString (hr), w, h, format);
return 0;
}
hr = t->LockRect (0, &locked, NULL, 0);
if (SUCCEEDED (hr)) {
int y;
int wb;
wb = w * 4;
if (wb > locked.Pitch)
wb = w * 2;
if (wb > locked.Pitch)
wb = w * 1;
for (y = 0; y < h; y++)
memset ((uae_u8*)locked.pBits + y * locked.Pitch, 0, wb);
t->UnlockRect (0);
}
return t;
}
static int allocextratextures (struct d3dstruct *d3d, struct shaderdata *s, int w, int h)
{
HRESULT hr;
if (FAILED (hr = d3d->d3ddev->CreateTexture (w, h, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &s->lpWorkTexture1, NULL))) {
write_log (_T("%s: Failed to create working texture1: %s:%d\n"), D3DHEAD, D3D_ErrorString (hr), s - &d3d->shaders[0]);
return 0;
}
if (FAILED (hr = d3d->d3ddev->CreateTexture (w, h, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &s->lpWorkTexture2, NULL))) {
write_log (_T("%s: Failed to create working texture2: %s:%d\n"), D3DHEAD, D3D_ErrorString (hr), s - &d3d->shaders[0]);
return 0;
}
write_log (_T("%s: %d*%d working texture:%d\n"), D3DHEAD, w, h, s - &d3d->shaders[0]);
return 1;
}
static int createamigatexture (struct d3dstruct *d3d, int w, int h)
{
HRESULT hr;
d3d->texture = createtext (d3d, w, h, d3d->tformat);
if (!d3d->texture)
return 0;
write_log (_T("%s: %d*%d main texture, depth %d\n"), D3DHEAD, w, h, d3d->t_depth);
if (d3d->psActive) {
for (int i = 0; i < MAX_SHADERS; i++) {
int w2, h2;
int type = d3d->shaders[i].type;
if (type == SHADERTYPE_BEFORE) {
w2 = d3d->shaders[i].worktex_width;
h2 = d3d->shaders[i].worktex_height;
if (!allocextratextures (d3d, &d3d->shaders[i], w, h))
return 0;
} else if (type == SHADERTYPE_MIDDLE) {
w2 = d3d->shaders[i].worktex_width;
h2 = d3d->shaders[i].worktex_height;
} else {
w2 = d3d->window_w;
h2 = d3d->window_h;
}
if (type == SHADERTYPE_BEFORE || type == SHADERTYPE_AFTER || type == SHADERTYPE_MIDDLE) {
D3DLOCKED_BOX lockedBox;
if (FAILED (hr = d3d->d3ddev->CreateVolumeTexture (256, 16, 256, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->shaders[i].lpHq2xLookupTexture, NULL))) {
write_log (_T("%s: Failed to create volume texture: %s:%d\n"), D3DHEAD, D3D_ErrorString (hr), i);
return 0;
}
if (FAILED (hr = d3d->shaders[i].lpHq2xLookupTexture->LockBox (0, &lockedBox, NULL, 0))) {
write_log (_T("%s: Failed to lock box of volume texture: %s:%d\n"), D3DHEAD, D3D_ErrorString (hr), i);
return 0;
}
write_log (_T("HQ2X texture (%dx%d) (%dx%d):%d\n"), w2, h2, w, h, i);
BuildHq2xLookupTexture (w2, h2, w, h, (unsigned char*)lockedBox.pBits);
d3d->shaders[i].lpHq2xLookupTexture->UnlockBox (0);
}
}
}
return 1;
}
static int createtexture (struct d3dstruct *d3d, int ow, int oh, int win_w, int win_h)
{
HRESULT hr;
bool haveafter = false;
int zw, zh;
if (ow > win_w * d3d->dmultxh && oh > win_h * d3d->dmultxv) {
zw = ow;
zh = oh;
} else {
zw = win_w * d3d->dmultxh;
zh = win_h * d3d->dmultxv;
}
for (int i = 0; i < MAX_SHADERS; i++) {
if (d3d->shaders[i].type == SHADERTYPE_BEFORE || d3d->shaders[i].type == SHADERTYPE_AFTER || d3d->shaders[i].type == SHADERTYPE_MIDDLE) {
int w2, h2, w, h;
if (d3d->shaders[i].type == SHADERTYPE_AFTER) {
w2 = zw; h2 = zh;
w = zw; h = zh;
haveafter = true;
if (!allocextratextures (d3d, &d3d->shaders[i], d3d->window_w, d3d->window_h))
return 0;
} else if (d3d->shaders[i].type == SHADERTYPE_MIDDLE) {
// worktex_width = 800
// extratex = amiga res
w2 = zw; h2 = zh;
w = zw; h = zh;
if (!allocextratextures (d3d, &d3d->shaders[i], ow, oh))
return 0;
} else {
w2 = ow;
h2 = oh;
w = ow;
h = oh;
}
d3d->shaders[i].targettex_width = w2;
d3d->shaders[i].targettex_height = h2;
if (FAILED (hr = d3d->d3ddev->CreateTexture (w2, h2, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->shaders[i].lpTempTexture, NULL))) {
write_log (_T("%s: Failed to create working texture1: %s:%d:%d\n"), D3DHEAD, D3D_ErrorString (hr), i, d3d->shaders[i].type);
return 0;
}
write_log (_T("%s: %d*%d temp texture:%d:%d\n"), D3DHEAD, w2, h2, i, d3d->shaders[i].type);
d3d->shaders[i].worktex_width = w;
d3d->shaders[i].worktex_height = h;
}
}
if (haveafter) {
if (FAILED (hr = d3d->d3ddev->CreateTexture (d3d->window_w, d3d->window_h, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->lpPostTempTexture, NULL))) {
write_log (_T("%s: Failed to create temp texture: %s\n"), D3DHEAD, D3D_ErrorString (hr));
return 0;
}
write_log (_T("%s: %d*%d after texture\n"), D3DHEAD, d3d->window_w, d3d->window_h);
}
return 1;
}
static void updateleds (struct d3dstruct *d3d)
{
D3DLOCKED_RECT locked;
HRESULT hr;
static uae_u32 rc[256], gc[256], bc[256], a[256];
static int done;
if (!done) {
for (int i = 0; i < 256; i++) {
rc[i] = i << 16;
gc[i] = i << 8;
bc[i] = i << 0;
a[i] = i << 24;
}
done = 1;
}
if (d3d != &d3ddata[0])
return;
hr = d3d->ledtexture->LockRect (0, &locked, NULL, D3DLOCK_DISCARD);
if (FAILED (hr)) {
write_log (_T("%d: SL LockRect failed: %s\n"), D3DHEAD, D3D_ErrorString (hr));
return;
}
for (int y = 0; y < TD_TOTAL_HEIGHT * d3d->statusbar_vx; y++) {
uae_u8 *buf = (uae_u8*)locked.pBits + y * locked.Pitch;
statusline_single_erase(d3d - d3ddata, buf, 32 / 8, y, d3d->ledwidth);
}
statusline_render(d3d - d3ddata, (uae_u8*)locked.pBits, 32 / 8, locked.Pitch, d3d->ledwidth, d3d->ledheight, rc, gc, bc, a);
for (int y = 0; y < TD_TOTAL_HEIGHT * d3d->statusbar_vx; y++) {
uae_u8 *buf = (uae_u8*)locked.pBits + y * locked.Pitch;
draw_status_line_single(d3d - d3ddata, buf, 32 / 8, y, d3d->ledwidth, rc, gc, bc, a);
}
d3d->ledtexture->UnlockRect (0);
}
static int createledtexture (struct d3dstruct *d3d)
{
struct AmigaMonitor *mon = &AMonitors[d3d - d3ddata];
d3d->statusbar_hx = d3d->statusbar_vx = statusline_set_multiplier(mon->monitor_id, d3d->tout_w, d3d->tout_h);
d3d->ledwidth = d3d->window_w;
d3d->ledheight = TD_TOTAL_HEIGHT * d3d->statusbar_vx;
d3d->ledtexture = createtext(d3d, d3d->ledwidth, d3d->ledheight * d3d->statusbar_vx, D3DFMT_A8R8G8B8);
if (!d3d->ledtexture)
return 0;
return 1;
}
static int createsltexture (struct d3dstruct *d3d)
{
d3d->sltexture = createtext (d3d, d3d->required_sl_texture_w, d3d->required_sl_texture_h, d3d->t_depth < 32 ? D3DFMT_A4R4G4B4 : D3DFMT_A8R8G8B8);
if (!d3d->sltexture)
return 0;
write_log (_T("%s: SL %d*%d texture allocated\n"), D3DHEAD, d3d->required_sl_texture_w, d3d->required_sl_texture_h);
d3d->maskmult_x = 1.0f;
d3d->maskmult_y = 1.0f;
return 1;
}
static void createscanlines (struct d3dstruct *d3d, int force)
{
HRESULT hr;
D3DLOCKED_RECT locked;
int sl4, sl42;
int l1, l2;
int x, y, yy;
uae_u8 *sld, *p;
int bpp;
if (d3d->scanline_osl1 == d3d->filterd3d->gfx_filter_scanlines &&
d3d->scanline_osl3 == d3d->filterd3d->gfx_filter_scanlinelevel &&
d3d->scanline_osl2 == d3d->filterd3d->gfx_filter_scanlineratio &&
d3d->scanline_osl4 == d3d->filterd3d->gfx_filter_scanlineoffset &&
!force)
return;
bpp = d3d->t_depth < 32 ? 2 : 4;
d3d->scanline_osl1 = d3d->filterd3d->gfx_filter_scanlines;
d3d->scanline_osl3 = d3d->filterd3d->gfx_filter_scanlinelevel;
d3d->scanline_osl2 = d3d->filterd3d->gfx_filter_scanlineratio;
d3d->scanline_osl4 = d3d->filterd3d->gfx_filter_scanlineoffset;
sl4 = d3d->filterd3d->gfx_filter_scanlines * 16 / 100;
sl42 = d3d->filterd3d->gfx_filter_scanlinelevel * 16 / 100;
if (sl4 > 15)
sl4 = 15;
if (sl42 > 15)
sl42 = 15;
l1 = (d3d->filterd3d->gfx_filter_scanlineratio >> 0) & 15;
l2 = (d3d->filterd3d->gfx_filter_scanlineratio >> 4) & 15;
if (l1 + l2 <= 0)
return;
if (!d3d->sltexture) {
if (d3d->scanline_osl1 == 0 && d3d->scanline_osl3 == 0)
return;
if (!createsltexture (d3d))
return;
}
hr = d3d->sltexture->LockRect (0, &locked, NULL, 0);
if (FAILED (hr)) {
write_log (_T("%s: SL LockRect failed: %s\n"), D3DHEAD, D3D_ErrorString (hr));
return;
}
sld = (uae_u8*)locked.pBits;
for (y = 0; y < d3d->required_sl_texture_h; y++) {
memset(sld + y * locked.Pitch, 0, d3d->required_sl_texture_w * bpp);
}
for (y = 0; y < d3d->required_sl_texture_h; y += l1 + l2) {
int y2 = y + (d3d->filterd3d->gfx_filter_scanlineoffset % (l1 + 1));
for (yy = 0; yy < l2 && y2 + yy < d3d->required_sl_texture_h; yy++) {
for (x = 0; x < d3d->required_sl_texture_w; x++) {
uae_u8 sll = sl42;
p = &sld[(y2 + yy) * locked.Pitch + (x * bpp)];
if (bpp < 4) {
/* 16-bit, A4R4G4B4 */
p[1] = (sl4 << 4) | (sll << 0);
p[0] = (sll << 4) | (sll << 0);
} else {
/* 32-bit, A8R8G8B8 */
uae_u8 sll4 = sl4 | (sl4 << 4);
uae_u8 sll2 = sll | (sll << 4);
p[0] = sll2;
p[1] = sll2;
p[2] = sll2;
p[3] = sll4;
}
}
}
}
d3d->sltexture->UnlockRect (0);
}
#include "png.h"
struct uae_image
{
uae_u8 *data;
int width, height, pitch;
};
struct png_cb
{
uae_u8 *ptr;
int size;
};
static void __cdecl readcallback(png_structp png_ptr, png_bytep out, png_size_t count)
{
png_voidp io_ptr = png_get_io_ptr(png_ptr);
if (!io_ptr)
return;
struct png_cb *cb = (struct png_cb*)io_ptr;
if (count > cb->size)
count = cb->size;
memcpy(out, cb->ptr, count);
cb->ptr += count;
cb->size -= count;
}
static bool load_png_image(struct zfile *zf, struct uae_image *img)
{
extern unsigned char test_card_png[];
extern unsigned int test_card_png_len;
uae_u8 *b = test_card_png;
uae_u8 *bfree = NULL;
png_structp png_ptr;
png_infop info_ptr;
png_uint_32 width, height;
int depth, color_type;
struct png_cb cb;
png_bytepp row_pp;
png_size_t cols;
bool ok = false;
memset(img, 0, sizeof(struct uae_image));
int size;
uae_u8 *bb = zfile_getdata(zf, 0, -1, &size);
if (!bb)
goto end;
b = bb;
bfree = bb;
if (!png_check_sig(b, 8))
goto end;
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
if (!png_ptr)
goto end;
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
png_destroy_read_struct(&png_ptr, 0, 0);
goto end;
}
cb.ptr = b;
cb.size = size;
png_set_read_fn(png_ptr, &cb, readcallback);
png_read_info(png_ptr, info_ptr);
png_get_IHDR(png_ptr, info_ptr, &width, &height, &depth, &color_type, 0, 0, 0);
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_expand(png_ptr);
if (color_type == PNG_COLOR_TYPE_GRAY && depth < 8)
png_set_expand(png_ptr);
if (depth > 8)
png_set_strip_16(png_ptr);
if (depth < 8)
png_set_packing(png_ptr);
if (!(color_type & PNG_COLOR_MASK_ALPHA))
png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER);
png_set_bgr(png_ptr);
cols = png_get_rowbytes(png_ptr, info_ptr);
img->pitch = width * 4;
img->width = width;
img->height = height;
row_pp = new png_bytep[height];
img->data = xcalloc(uae_u8, width * height * 4);
for (int i = 0; i < height; i++) {
row_pp[i] = (png_bytep)&img->data[i * img->pitch];
}
png_read_image(png_ptr, row_pp);
png_read_end(png_ptr, info_ptr);
png_destroy_read_struct(&png_ptr, &info_ptr, 0);
delete[] row_pp;
ok = true;
end:
xfree(bfree);
return ok;
}
static void free_uae_image(struct uae_image *img)
{
if (!img)
return;
xfree(img->data);
img->data = NULL;
}
static int findedge(struct uae_image *img, int w, int h, int dx, int dy)
{
int x = w / 2;
int y = h / 2;
if (dx != 0)
x = dx < 0 ? 0 : w - 1;
if (dy != 0)
y = dy < 0 ? 0 : h - 1;
for (;;) {
uae_u32 *p = (uae_u32*)(img->data + y * img->pitch + x * 4);
int alpha = (*p) >> 24;
if (alpha != 255)
break;
x -= dx;
y -= dy;
if (x <= 0 || y <= 0)
break;
if (x >= w - 1 || y >= h - 1)
break;
}
if (dx)
return x;
return y;
}
static void narrowimg(struct uae_image *img, int *xop, int *yop, const TCHAR *name)
{
int x1, x2, y1, y2;
for (y1 = 0; y1 < img->height; y1++) {
bool tline = true;
for (int x = 0; x < img->width; x++) {
uae_u8 *p = img->data + y1 * img->pitch + x * 4;
if (p[3] != 0x00)
tline = false;
}
if (!tline)
break;
}
for (y2 = img->height - 1; y2 >= y1; y2--) {
bool tline = true;
for (int x = 0; x < img->width; x++) {
uae_u8 *p = img->data + y2 * img->pitch + x * 4;
if (p[3] != 0x00)
tline = false;
}
if (!tline)
break;
}
for (x1 = 0; x1 < img->width; x1++) {
bool tline = true;
for (int y = y1; y <= y2; y++) {
uae_u8 *p = img->data + y * img->pitch + x1 * 4;
if (p[3] != 0x00)
tline = false;
}
if (!tline)
break;
}
for (x2 = img->width - 1; x2 >= x1; x2--) {
bool tline = true;
for (int y = y1; y <= y2; y++) {
uae_u8 *p = img->data + y * img->pitch + x2 * 4;
if (p[3] != 0x00)
tline = false;
}
if (!tline)
break;
}
int w = x2 - x1 + 1;
int h = y2 - y1 + 1;
int pitch = w * 4;
*xop = x1;
*yop = y1;
uae_u8 *d = xcalloc(uae_u8, img->width * img->height * 4);
for (int y = 0; y < h; y++) {
uae_u8 *dp = d + y * pitch;
uae_u8 *sp = img->data + (y + y1) * img->pitch + x1 * 4;
memcpy(dp, sp, w * 4);
}
write_log(_T("Overlay LED: '%s' %d*%d -> %d*%d (%d*%d - %d*%d)\n"), name, img->width, img->height, w, h, x1, y1, x2, y2);
xfree(img->data);
img->width = w;
img->height = h;
img->pitch = pitch;
img->data = d;
}
static uae_u8 dimming(uae_u8 v)
{
return v * currprefs.power_led_dim / 100;
}
static int createmask2texture (struct d3dstruct *d3d, const TCHAR *filename)
{
struct AmigaMonitor *mon = &AMonitors[d3d - d3ddata];
struct zfile *zf;
LPDIRECT3DTEXTURE9 tx;
HRESULT hr;
TCHAR tmp[MAX_DPATH];
TCHAR filepath[MAX_DPATH];
D3DLOCKED_RECT locked;
if (d3d->mask2texture)
d3d->mask2texture->Release();
d3d->mask2texture = NULL;
for (int i = 0; overlayleds[i]; i++) {
if (d3d->mask2textureleds[i])
d3d->mask2textureleds[i]->Release();
d3d->mask2textureleds[i] = NULL;
}
if (d3d->mask2textureled_power_dim)
d3d->mask2textureled_power_dim->Release();
d3d->mask2textureled_power_dim = NULL;
if (filename[0] == 0)
return 0;
zf = NULL;
for (int i = 0; i < 2; i++) {
if (i == 0) {
get_plugin_path (tmp, sizeof tmp / sizeof (TCHAR), _T("overlays"));
_tcscat (tmp, filename);
} else {
_tcscpy (tmp, filename);
}
TCHAR tmp2[MAX_DPATH], tmp3[MAX_DPATH];
_tcscpy (tmp3, tmp);
TCHAR *s = _tcsrchr (tmp3, '.');
if (s) {
TCHAR *s2 = s;
while (s2 > tmp3) {
TCHAR v = *s2;
if (v == '_') {
s = s2;
break;
}
if (v == 'X' || v == 'x') {
s2--;
continue;
}
if (!_istdigit (v))
break;
s2--;
}
_tcscpy (tmp2, s);
_stprintf (s, _T("_%dx%d%s"), d3d->window_w, d3d->window_h, tmp2);
_tcscpy(filepath, tmp3);
zf = zfile_fopen (tmp3, _T("rb"), ZFD_NORMAL);
if (zf)
break;
float aspect = (float)d3d->window_w / d3d->window_h;
int ax = -1, ay = -1;
if (abs (aspect - 16.0 / 10.0) <= 0.1)
ax = 16, ay = 10;
if (abs (aspect - 16.0 / 9.0) <= 0.1)
ax = 16, ay = 9;
if (abs (aspect - 4.0 / 3.0) <= 0.1)
ax = 4, ay = 3;
if (ax > 0 && ay > 0) {
_stprintf (s, _T("_%dx%d%s"), ax, ay, tmp2);
_tcscpy(filepath, tmp3);
zf = zfile_fopen (tmp3, _T("rb"), ZFD_NORMAL);
if (zf)
break;
}
}
_tcscpy(filepath, tmp);
zf = zfile_fopen (tmp, _T("rb"), ZFD_NORMAL);
if (zf)
break;
}
if (!zf) {
write_log (_T("%s: couldn't open overlay '%s'\n"), D3DHEAD, filename);
return 0;
}
struct uae_image img;
if (!load_png_image(zf, &img)) {
write_log(_T("Overlay texture '%s' load failed.\n"), filename);
goto end;
}
tx = createtext(d3d, img.width, img.height, D3DFMT_A8R8G8B8);
if (!tx) {
write_log(_T("%s: overlay texture load failed.\n"), D3DHEAD);
goto end;
}
d3d->mask2texture_w = img.width;
d3d->mask2texture_h = img.height;
d3d->mask2texture = tx;
hr = tx->LockRect(0, &locked, NULL, 0);
if (FAILED(hr)) {
write_log(_T("%s: Overlay LockRect failed: %s\n"), D3DHEAD, D3D_ErrorString(hr));
goto end;
}
for (int i = 0; i < img.height; i++) {
memcpy((uae_u8*)locked.pBits + i * locked.Pitch, img.data + i * img.pitch, img.width * 4);
}
tx->UnlockRect(0);
d3d->mask2rect.left = findedge(&img, d3d->mask2texture_w, d3d->mask2texture_h, -1, 0);
d3d->mask2rect.right = findedge(&img, d3d->mask2texture_w, d3d->mask2texture_h, 1, 0);
d3d->mask2rect.top = findedge(&img, d3d->mask2texture_w, d3d->mask2texture_h, 0, -1);
d3d->mask2rect.bottom = findedge(&img, d3d->mask2texture_w, d3d->mask2texture_h, 0, 1);
if (d3d->mask2rect.left >= d3d->mask2texture_w / 2 || d3d->mask2rect.top >= d3d->mask2texture_h / 2 ||
d3d->mask2rect.right <= d3d->mask2texture_w / 2 || d3d->mask2rect.bottom <= d3d->mask2texture_h / 2) {
d3d->mask2rect.left = 0;
d3d->mask2rect.top = 0;
d3d->mask2rect.right = d3d->mask2texture_w;
d3d->mask2rect.bottom = d3d->mask2texture_h;
}
d3d->mask2texture_multx = (float)d3d->window_w / d3d->mask2texture_w;
d3d->mask2texture_multy = (float)d3d->window_h / d3d->mask2texture_h;
d3d->mask2texture_offsetw = 0;
if (isfullscreen () > 0) {
struct MultiDisplay *md = getdisplay(&currprefs, mon->monitor_id);
float deskw = md->rect.right - md->rect.left;
float deskh = md->rect.bottom - md->rect.top;
//deskw = 800; deskh = 600;
float dstratio = deskw / deskh;
float srcratio = d3d->mask2texture_w / d3d->mask2texture_h;
d3d->mask2texture_multx *= srcratio / dstratio;
} else {
d3d->mask2texture_multx = d3d->mask2texture_multy;
}
d3d->mask2texture_wh = d3d->window_h;
d3d->mask2texture_ww = d3d->mask2texture_w * d3d->mask2texture_multx;
d3d->mask2texture_offsetw = (d3d->window_w - d3d->mask2texture_ww) / 2;
if (d3d->mask2texture_offsetw > 0)
d3d->blanktexture = createtext (d3d, d3d->mask2texture_offsetw + 1, d3d->window_h, D3DFMT_X8R8G8B8);
float xmult = d3d->mask2texture_multx;
float ymult = d3d->mask2texture_multy;
d3d->mask2rect.left *= xmult;
d3d->mask2rect.right *= xmult;
d3d->mask2rect.top *= ymult;
d3d->mask2rect.bottom *= ymult;
d3d->mask2texture_wwx = d3d->mask2texture_w * xmult;
if (d3d->mask2texture_wwx > d3d->window_w)
d3d->mask2texture_wwx = d3d->window_w;
if (d3d->mask2texture_wwx < d3d->mask2rect.right - d3d->mask2rect.left)
d3d->mask2texture_wwx = d3d->mask2rect.right - d3d->mask2rect.left;
if (d3d->mask2texture_wwx > d3d->mask2texture_ww)
d3d->mask2texture_wwx = d3d->mask2texture_ww;
d3d->mask2texture_minusx = - ((d3d->window_w - d3d->mask2rect.right) + d3d->mask2rect.left);
if (d3d->mask2texture_offsetw > 0)
d3d->mask2texture_minusx += d3d->mask2texture_offsetw * xmult;
d3d->mask2texture_minusy = -(d3d->window_h - (d3d->mask2rect.bottom - d3d->mask2rect.top));
d3d->mask2texture_hhx = d3d->mask2texture_h * ymult;
write_log (_T("%s: overlay '%s' %.0f*%.0f (%d*%d - %d*%d) (%d*%d)\n"),
D3DHEAD, tmp, d3d->mask2texture_w, d3d->mask2texture_h,
d3d->mask2rect.left, d3d->mask2rect.top, d3d->mask2rect.right, d3d->mask2rect.bottom,
d3d->mask2rect.right - d3d->mask2rect.left, d3d->mask2rect.bottom - d3d->mask2rect.top);
for (int i = 0; overlayleds[i]; i++) {
if (!overlayleds[i][0])
continue;
TCHAR tmp1[MAX_DPATH];
_tcscpy(tmp1, filepath);
_tcscpy(tmp1 + _tcslen(tmp1) - 4, _T("_"));
_tcscpy(tmp1 + _tcslen(tmp1), overlayleds[i]);
_tcscat(tmp1, _T("_led"));
_tcscat(tmp1, filepath + _tcslen(filepath) - 4);
zf = zfile_fopen(tmp1, _T("rb"), ZFD_NORMAL);
if (zf) {
struct uae_image ledimg;
if (load_png_image(zf, &ledimg)) {
if (ledimg.width == img.width && ledimg.height == img.height) {
narrowimg(&ledimg, &d3d->mask2textureledoffsets[i * 2 + 0], &d3d->mask2textureledoffsets[i * 2 + 1], tmp1);
d3d->mask2textureleds[i] = createtext(d3d, ledimg.width, ledimg.height, D3DFMT_A8R8G8B8);
if (d3d->mask2textureleds[i]) {
hr = d3d->mask2textureleds[i]->LockRect(0, &locked, NULL, 0);
if (SUCCEEDED(hr)) {
for (int j = 0; j < ledimg.height; j++) {
memcpy((uae_u8*)locked.pBits + j * locked.Pitch, ledimg.data + j * ledimg.pitch, ledimg.width * 4);
}
d3d->mask2textureleds[i]->UnlockRect(0);
}
}
if (ledtypes[i] == LED_POWER) {
d3d->mask2textureled_power_dim = createtext(d3d, ledimg.width, ledimg.height, D3DFMT_A8R8G8B8);
if (d3d->mask2textureled_power_dim) {
hr = d3d->mask2textureled_power_dim->LockRect(0, &locked, NULL, 0);
if (SUCCEEDED(hr)) {
for (int j = 0; j < ledimg.height; j++) {
uae_u8 *pd = (uae_u8*)locked.pBits + j * locked.Pitch;
uae_u8 *ps = ledimg.data + j * ledimg.pitch;
for (int k = 0; k < ledimg.width; k++) {
pd[0] = dimming(ps[0]);
pd[1] = dimming(ps[1]);
pd[2] = dimming(ps[2]);
pd[3] = ps[3];
pd += 4;
ps += 4;
}
}
d3d->mask2textureled_power_dim->UnlockRect(0);
}
}
}
} else {
write_log(_T("Overlay led '%s' size mismatch.\n"), tmp1);
}
free_uae_image(&ledimg);
} else {
write_log(_T("Overlay led '%s' load failed.\n"), tmp1);
}
zfile_fclose(zf);
}
}
free_uae_image(&img);
return 1;
end:
free_uae_image(&img);
if (tx)
tx->Release ();
if (d3d->blanktexture)
d3d->blanktexture->Release();
d3d->blanktexture = NULL;
return 0;
}
static int createmasktexture (struct d3dstruct *d3d, const TCHAR *filename, struct shaderdata *sd)
{
struct zfile *zf;
int size;
uae_u8 *buf;
D3DSURFACE_DESC maskdesc, txdesc;
LPDIRECT3DTEXTURE9 tx;
HRESULT hr;
D3DLOCKED_RECT lock, slock;
D3DXIMAGE_INFO dinfo;
TCHAR tmp[MAX_DPATH];
int maskwidth, maskheight;
int idx = sd - &d3d->shaders[0];
if (filename[0] == 0)
return 0;
tx = NULL;
get_plugin_path (tmp, sizeof tmp / sizeof (TCHAR), _T("masks"));
_tcscat (tmp, filename);
zf = zfile_fopen (tmp, _T("rb"), ZFD_NORMAL);
if (!zf) {
zf = zfile_fopen (filename, _T("rb"), ZFD_NORMAL);
if (!zf) {
write_log (_T("%s: couldn't open mask '%s':%d\n"), D3DHEAD, filename, idx);
return 0;
}
}
size = zfile_size (zf);
buf = xmalloc (uae_u8, size);
zfile_fread (buf, size, 1, zf);
zfile_fclose (zf);
hr = D3DXCreateTextureFromFileInMemoryEx (d3d->d3ddev, buf, size,
D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2, 1, D3DUSAGE_DYNAMIC, D3DFMT_X8R8G8B8,
D3DPOOL_DEFAULT, D3DX_FILTER_NONE, D3DX_FILTER_NONE, 0, &dinfo, NULL, &tx);
xfree (buf);
if (FAILED (hr)) {
write_log (_T("%s: temp mask texture load failed: %s:%d\n"), D3DHEAD, D3D_ErrorString (hr), idx);
goto end;
}
hr = tx->GetLevelDesc (0, &txdesc);
if (FAILED (hr)) {
write_log (_T("%s: mask image texture GetLevelDesc() failed: %s:%d\n"), D3DHEAD, D3D_ErrorString (hr), idx);
goto end;
}
sd->masktexture_w = dinfo.Width;
sd->masktexture_h = dinfo.Height;
#if 0
if (txdesc.Width == masktexture_w && txdesc.Height == masktexture_h && psEnabled) {
// texture size == image size, no need to tile it (Wrap sampler does the rest)
if (masktexture_w < window_w || masktexture_h < window_h) {
maskwidth = window_w;
maskheight = window_h;
} else {
masktexture = tx;
tx = NULL;
}
} else {
#endif
// both must be divisible by mask size
maskwidth = ((d3d->window_w + sd->masktexture_w - 1) / sd->masktexture_w) * sd->masktexture_w;
maskheight = ((d3d->window_h + sd->masktexture_h - 1) / sd->masktexture_h) * sd->masktexture_h;
#if 0
}
#endif
if (tx) {
sd->masktexture = createtext (d3d, maskwidth, maskheight, D3DFMT_X8R8G8B8);
if (FAILED (hr)) {
write_log (_T("%s: mask texture creation failed: %s:%d\n"), D3DHEAD, D3D_ErrorString (hr), idx);
goto end;
}
hr = sd->masktexture->GetLevelDesc (0, &maskdesc);
if (FAILED (hr)) {
write_log (_T("%s: mask texture GetLevelDesc() failed: %s:%d\n"), D3DHEAD, D3D_ErrorString (hr), idx);
goto end;
}
if (SUCCEEDED (hr = sd->masktexture->LockRect (0, &lock, NULL, 0))) {
if (SUCCEEDED (hr = tx->LockRect (0, &slock, NULL, 0))) {
int x, y, sx, sy;
uae_u32 *sptr, *ptr;
sy = 0;
for (y = 0; y < maskdesc.Height; y++) {
sx = 0;
for (x = 0; x < maskdesc.Width; x++) {
uae_u32 v;
sptr = (uae_u32*)((uae_u8*)slock.pBits + sy * slock.Pitch + sx * 4);
ptr = (uae_u32*)((uae_u8*)lock.pBits + y * lock.Pitch + x * 4);
v = *sptr;
// v &= 0x00FFFFFF;
// v |= 0x80000000;
*ptr = v;
sx++;
if (sx >= dinfo.Width)
sx = 0;
}
sy++;
if (sy >= dinfo.Height)
sy = 0;
}
tx->UnlockRect (0);
}
sd->masktexture->UnlockRect (0);
}
tx->Release ();
sd->masktexture_w = maskdesc.Width;
sd->masktexture_h = maskdesc.Height;
}
write_log (_T("%s: mask %d*%d (%d*%d) %d*%d ('%s':%d) texture allocated\n"), D3DHEAD, sd->masktexture_w, sd->masktexture_h, txdesc.Width, txdesc.Height, maskdesc.Width, maskdesc.Height, filename, idx);
d3d->maskmult_x = (float)d3d->window_w / sd->masktexture_w;
d3d->maskmult_y = (float)d3d->window_h / sd->masktexture_h;
return 1;
end:
if (sd->masktexture)
sd->masktexture->Release ();
sd->masktexture = NULL;
if (tx)
tx->Release ();
return 0;
}
static bool xD3D_getscalerect(int monid, float *mx, float *my, float *sx, float *sy, int width, int height)
{
struct d3dstruct *d3d = &d3ddata[monid];
struct vidbuf_description *vidinfo = &adisplays[monid].gfxvidinfo;
if (!d3d->mask2texture)
return false;
float mw = d3d->mask2rect.right - d3d->mask2rect.left;
float mh = d3d->mask2rect.bottom - d3d->mask2rect.top;
float mxt = (float)mw / width;
float myt = (float)mh / height;
*mx = d3d->mask2texture_minusx / mxt;
*my = d3d->mask2texture_minusy / myt;
*sx = -((d3d->mask2texture_ww - d3d->mask2rect.right) - (d3d->mask2rect.left)) / 2;
*sy = -((d3d->mask2texture_wh - d3d->mask2rect.bottom) - (d3d->mask2rect.top)) / 2;
*sx /= mxt;
*sy /= myt;
return true;
}
static void setupscenecoords (struct d3dstruct *d3d, bool normalrender)
{
int monid = d3d - d3ddata;
struct vidbuf_description *vidinfo = &adisplays[monid].gfxvidinfo;
RECT sr, dr, zr;
float w, h;
float dw, dh;
static RECT sr2[MAX_AMIGAMONITORS], dr2[MAX_AMIGAMONITORS], zr2[MAX_AMIGAMONITORS];
if (!normalrender)
return;
//write_log (_T("%dx%d %dx%d %dx%d\n"), tin_w, tin_h, tin_w, tin_h, window_w, window_h);
getfilterrect2 (monid, &dr, &sr, &zr, d3d->window_w, d3d->window_h, d3d->tin_w / d3d->dmult, d3d->tin_h / d3d->dmult, d3d->dmult, d3d->tin_w, d3d->tin_h);
if (memcmp (&sr, &sr2[monid], sizeof RECT) || memcmp (&dr, &dr2[monid], sizeof RECT) || memcmp (&zr, &zr2[monid], sizeof RECT)) {
write_log (_T("POS (%d %d %d %d) - (%d %d %d %d)[%d,%d] (%d %d)\n"),
dr.left, dr.top, dr.right, dr.bottom, sr.left, sr.top, sr.right, sr.bottom,
sr.right - sr.left, sr.bottom - sr.top,
zr.left, zr.top);
sr2[monid] = sr;
dr2[monid] = dr;
zr2[monid] = zr;
}
dw = dr.right - dr.left;
dh = dr.bottom - dr.top;
w = sr.right - sr.left;
h = sr.bottom - sr.top;
d3d->fakesize.x = w;
d3d->fakesize.y = h;
d3d->fakesize.w = 1;
d3d->fakesize.z = 1;
MatrixOrthoOffCenterLH (&d3d->m_matProj_out, 0, w + 0.05f, 0, h + 0.05f, 0.0f, 1.0f);
float tx, ty;
float sw, sh;
if (0 && d3d->mask2texture) {
float mw = d3d->mask2rect.right - d3d->mask2rect.left;
float mh = d3d->mask2rect.bottom - d3d->mask2rect.top;
tx = -0.5f + dw * d3d->tin_w / mw / 2;
ty = +0.5f + dh * d3d->tin_h / mh / 2;
float xshift = -zr.left;
float yshift = -zr.top;
sw = dw * d3d->tin_w / vidinfo->outbuffer->inwidth2;
sw *= mw / d3d->window_w;
tx = -0.5f + d3d->window_w / 2;
sh = dh * d3d->tin_h / vidinfo->outbuffer->inheight2;
sh *= mh / d3d->window_h;
ty = +0.5f + d3d->window_h / 2;
tx += xshift;
ty += yshift;
} else {
tx = -0.5f + dw * d3d->tin_w / d3d->window_w / 2;
ty = +0.5f + dh * d3d->tin_h / d3d->window_h / 2;
float xshift = - zr.left - sr.left; // - (tin_w - 2 * zr.left - w),
float yshift = + zr.top + sr.top - (d3d->tin_h - h);
sw = dw * d3d->tin_w / d3d->window_w;
sh = dh * d3d->tin_h / d3d->window_h;
//sw -= 0.5f;
//sh += 0.5f;
tx += xshift;
ty += yshift;
}
MatrixTranslation (&d3d->m_matView_out, tx, ty, 1.0f);
MatrixScaling (&d3d->m_matWorld_out, sw + 0.5f / sw, sh + 0.5f / sh, 1.0f);
d3d->cursor_offset_x = -zr.left;
d3d->cursor_offset_y = -zr.top;
//write_log (_T("%.1fx%.1f %.1fx%.1f %.1fx%.1f\n"), dw, dh, w, h, sw, sh);
// ratio between Amiga texture and overlay mask texture
float sw2 = dw * d3d->tin_w / d3d->window_w;
float sh2 = dh * d3d->tin_h / d3d->window_h;
//sw2 -= 0.5f;
//sh2 += 0.5f;
d3d->maskmult.x = sw2 * d3d->maskmult_x / w;
d3d->maskmult.y = sh2 * d3d->maskmult_y / h;
d3d->maskshift.x = 1.0f / d3d->maskmult_x;
d3d->maskshift.y = 1.0f / d3d->maskmult_y;
D3DXMATRIXA16 tmpmatrix;
D3DXMatrixMultiply (&tmpmatrix, &d3d->m_matWorld_out, &d3d->m_matView_out);
D3DXMatrixMultiply (&d3d->postproj, &tmpmatrix, &d3d->m_matProj_out);
}
#if 0
uae_u8 *getfilterbuffer3d(struct vidbuffer *vb, int *widthp, int *heightp, int *pitch, int *depth)
{
struct d3dstruct *d3d = &d3ddata[0];
RECT dr, sr, zr;
uae_u8 *p;
int w, h;
*depth = d3d->t_depth;
getfilterrect2 (&dr, &sr, &zr, d3d->window_w, d3d->window_h, d3d->tin_w / d3d->dmult, d3d->tin_h / d3d->dmult, d3d->dmult, d3d->tin_w, d3d->tin_h);
w = sr.right - sr.left;
h = sr.bottom - sr.top;
p = vb->bufmem;
if (pitch)
*pitch = vb->rowbytes;
p += (zr.top - h / 2) * vb->rowbytes + (zr.left - w / 2) * d3d->t_depth / 8;
*widthp = w;
*heightp = h;
return p;
}
#endif
static void createvertex (struct d3dstruct *d3d)
{
HRESULT hr;
struct TLVERTEX *vertices;
float sizex, sizey;
sizex = 1.0f;
sizey = 1.0f;
if (FAILED (hr = d3d->vertexBuffer->Lock (0, 0, (void**)&vertices, 0))) {
write_log (_T("%s: Vertexbuffer lock failed: %s\n"), D3DHEAD, D3D_ErrorString (hr));
return;
}
memset (vertices, 0, sizeof (struct TLVERTEX) * NUMVERTICES);
//Setup vertices
vertices[0].position.x = -0.5f; vertices[0].position.y = -0.5f;
vertices[0].diffuse = 0xFFFFFFFF;
vertices[0].texcoord.x = 0.0f; vertices[0].texcoord.y = sizey;
vertices[1].position.x = -0.5f; vertices[1].position.y = 0.5f;
vertices[1].diffuse = 0xFFFFFFFF;
vertices[1].texcoord.x = 0.0f; vertices[1].texcoord.y = 0.0f;
vertices[2].position.x = 0.5f; vertices[2].position.y = -0.5f;
vertices[2].diffuse = 0xFFFFFFFF;
vertices[2].texcoord.x = sizex; vertices[2].texcoord.y = sizey;
vertices[3].position.x = 0.5f; vertices[3].position.y = 0.5f;
vertices[3].diffuse = 0xFFFFFFFF;
vertices[3].texcoord.x = sizex; vertices[3].texcoord.y = 0.0f;
// Additional vertices required for some PS effects
vertices[4].position.x = 0.0f; vertices[4].position.y = 0.0f;
vertices[4].diffuse = 0xFFFFFF00;
vertices[4].texcoord.x = 0.0f; vertices[4].texcoord.y = 1.0f;
vertices[5].position.x = 0.0f; vertices[5].position.y = 1.0f;
vertices[5].diffuse = 0xFFFFFF00;
vertices[5].texcoord.x = 0.0f; vertices[5].texcoord.y = 0.0f;
vertices[6].position.x = 1.0f; vertices[6].position.y = 0.0f;
vertices[6].diffuse = 0xFFFFFF00;
vertices[6].texcoord.x = 1.0f; vertices[6].texcoord.y = 1.0f;
vertices[7].position.x = 1.0f; vertices[7].position.y = 1.0f;
vertices[7].diffuse = 0xFFFFFF00;
vertices[7].texcoord.x = 1.0f; vertices[7].texcoord.y = 0.0f;
if (FAILED(hr = d3d->vertexBuffer->Unlock ()))
write_log (_T("%s: Vertexbuffer unlock failed: %s\n"), D3DHEAD, D3D_ErrorString (hr));
}
static void settransform_pre (struct d3dstruct *d3d, struct shaderdata *s)
{
// Projection is (0,0,0) -> (1,1,1)
MatrixOrthoOffCenterLH (&d3d->m_matProj, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
// Align texels with pixels
MatrixTranslation (&d3d->m_matView, -0.5f / d3d->tout_w, 0.5f / d3d->tout_h, 0.0f);
// Identity for world
D3DXMatrixIdentity (&d3d->m_matWorld);
}
static void settransform (struct d3dstruct *d3d, struct shaderdata *s)
{
// Projection is (0,0,0) -> (1,1,1)
MatrixOrthoOffCenterLH (&d3d->m_matPreProj, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
// Align texels with pixels
MatrixTranslation (&d3d->m_matPreView, -0.5f / d3d->tout_w, 0.5f / d3d->tout_h, 0.0f);
// Identity for world
D3DXMatrixIdentity (&d3d->m_matPreWorld);
if (s)
psEffect_SetMatrices (&d3d->m_matProj, &d3d->m_matView, &d3d->m_matWorld, s);
MatrixOrthoOffCenterLH (&d3d->m_matProj2, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
MatrixTranslation (&d3d->m_matView2, 0.5f - 0.5f / d3d->tout_w, 0.5f + 0.5f / d3d->tout_h, 0.0f);
D3DXMatrixIdentity (&d3d->m_matWorld2);
}
static void settransform2 (struct d3dstruct *d3d, struct shaderdata *s)
{
// Projection is (0,0,0) -> (1,1,1)
MatrixOrthoOffCenterLH (&d3d->m_matPreProj, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
// Align texels with pixels
MatrixTranslation (&d3d->m_matPreView, -0.5f / d3d->window_w, 0.5f / d3d->window_h, 0.0f);
// Identity for world
D3DXMatrixIdentity (&d3d->m_matPreWorld);
MatrixOrthoOffCenterLH (&d3d->m_matProj2, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
MatrixTranslation (&d3d->m_matView2, 0.5f - 0.5f / d3d->window_w, 0.5f + 0.5f / d3d->window_h, 0.0f);
D3DXMatrixIdentity (&d3d->m_matWorld2);
}
static void freetextures (struct d3dstruct *d3d)
{
if (d3d->texture) {
d3d->texture->Release ();
d3d->texture = NULL;
}
for (int i = 0; i < MAX_SHADERS; i++) {
struct shaderdata *s = &d3d->shaders[i];
if (s->lpTempTexture) {
s->lpTempTexture->Release ();
s->lpTempTexture = NULL;
}
if (s->lpWorkTexture1) {
s->lpWorkTexture1->Release ();
s->lpWorkTexture1 = NULL;
}
if (s->lpWorkTexture2) {
s->lpWorkTexture2->Release ();
s->lpWorkTexture2 = NULL;
}
if (s->lpHq2xLookupTexture) {
s->lpHq2xLookupTexture->Release ();
s->lpHq2xLookupTexture = NULL;
}
}
if (d3d->lpPostTempTexture) {
d3d->lpPostTempTexture->Release();
d3d->lpPostTempTexture = NULL;
}
}
static void getswapchain (struct d3dstruct *d3d)
{
if (!d3d->d3dswapchain) {
HRESULT hr = d3d->d3ddev->GetSwapChain (0, &d3d->d3dswapchain);
if (FAILED (hr)) {
write_log (_T("%s: GetSwapChain() failed, %s\n"), D3DHEAD, D3D_ErrorString (hr));
}
}
}
static void invalidatedeviceobjects (struct d3dstruct *d3d)
{
if (d3d->filenotificationhandle != NULL)
FindCloseChangeNotification (d3d->filenotificationhandle);
d3d->filenotificationhandle = NULL;
freetextures (d3d);
if (d3d->query) {
d3d->query->Release();
d3d->query = NULL;
}
if (d3d->sprite) {
d3d->sprite->Release ();
d3d->sprite = NULL;
}
if (d3d->ledtexture) {
d3d->ledtexture->Release ();
d3d->ledtexture = NULL;
}
if (d3d->sltexture) {
d3d->sltexture->Release ();
d3d->sltexture = NULL;
}
if (d3d->mask2texture) {
d3d->mask2texture->Release ();
d3d->mask2texture = NULL;
}
for (int i = 0; overlayleds[i]; i++) {
if (d3d->mask2textureleds[i])
d3d->mask2textureleds[i]->Release();
d3d->mask2textureleds[i] = NULL;
}
if (d3d->mask2textureled_power_dim) {
d3d->mask2textureled_power_dim->Release();
d3d->mask2textureled_power_dim = NULL;
}
if (d3d->blanktexture) {
d3d->blanktexture->Release ();
d3d->blanktexture = NULL;
}
if (d3d->cursorsurfaced3d) {
d3d->cursorsurfaced3d->Release ();
d3d->cursorsurfaced3d = NULL;
}
struct d3d9overlay *ov = d3d->extoverlays;
while (ov) {
struct d3d9overlay *next = ov->next;
if (ov->tex)
ov->tex->Release();
xfree(ov);
ov = next;
}
d3d->extoverlays = NULL;
for (int i = 0; i < MAX_SHADERS; i++) {
if (d3d->shaders[i].pEffect) {
d3d->shaders[i].pEffect->Release ();
d3d->shaders[i].pEffect = NULL;
}
if (d3d->shaders[i].masktexture) {
d3d->shaders[i].masktexture->Release ();
d3d->shaders[i].masktexture = NULL;
}
memset (&d3d->shaders[i], 0, sizeof (struct shaderdata));
}
postEffect_freeParameters(d3d);
if (d3d->d3ddev)
d3d->d3ddev->SetStreamSource (0, NULL, 0, 0);
if (d3d->vertexBuffer) {
d3d->vertexBuffer->Release ();
d3d->vertexBuffer = NULL;
}
if (d3d->d3dswapchain) {
d3d->d3dswapchain->Release ();
d3d->d3dswapchain = NULL;
}
d3d->locked = 0;
d3d->maskshift.x = d3d->maskshift.y = d3d->maskshift.z = d3d->maskshift.w = 0;
d3d->maskmult.x = d3d->maskmult.y = d3d->maskmult.z = d3d->maskmult.w = 0;
}
static struct shaderdata *allocshaderslot (struct d3dstruct *d3d, int type)
{
for (int i = 0; i < MAX_SHADERS; i++) {
if (d3d->shaders[i].type == 0) {
d3d->shaders[i].type = type;
return &d3d->shaders[i];
}
}
return NULL;
}
static int restoredeviceobjects (struct d3dstruct *d3d)
{
int vbsize;
int wasshader = shaderon;
HRESULT hr;
invalidatedeviceobjects (d3d);
getswapchain (d3d);
while (shaderon > 0) {
d3d->shaders[SHADER_POST].type = SHADERTYPE_POST;
if (!psEffect_LoadEffect (d3d, d3d->psEnabled ? _T("_winuae.fx") : _T("_winuae_old.fx"), false, &d3d->shaders[SHADER_POST], -1)) {
shaderon = 0;
break;
}
for (int i = 0; i < MAX_FILTERSHADERS; i++) {
if (d3d->filterd3d->gfx_filtershader[i][0]) {
struct shaderdata *s = allocshaderslot (d3d, SHADERTYPE_BEFORE);
if (!psEffect_LoadEffect (d3d, d3d->filterd3d->gfx_filtershader[i], true, s, i)) {
d3d->filterd3d->gfx_filtershader[i][0] = changed_prefs.gf[d3d->filterd3didx].gfx_filtershader[i][0] = 0;
break;
}
}
if (d3d->filterd3d->gfx_filtermask[i][0]) {
struct shaderdata *s = allocshaderslot (d3d, SHADERTYPE_MASK_BEFORE);
createmasktexture (d3d, d3d->filterd3d->gfx_filtermask[i], s);
}
}
if (d3d->filterd3d->gfx_filtershader[2 * MAX_FILTERSHADERS][0]) {
struct shaderdata *s = allocshaderslot (d3d, SHADERTYPE_MIDDLE);
if (!psEffect_LoadEffect (d3d, d3d->filterd3d->gfx_filtershader[2 * MAX_FILTERSHADERS], true, s, 2 * MAX_FILTERSHADERS)) {
d3d->filterd3d->gfx_filtershader[2 * MAX_FILTERSHADERS][0] = changed_prefs.gf[d3d->filterd3didx].gfx_filtershader[2 * MAX_FILTERSHADERS][0] = 0;
}
}
if (d3d->filterd3d->gfx_filtermask[2 * MAX_FILTERSHADERS][0]) {
struct shaderdata *s = allocshaderslot (d3d, SHADERTYPE_MASK_MIDDLE);
createmasktexture (d3d, d3d->filterd3d->gfx_filtermask[2 * MAX_FILTERSHADERS], s);
}
for (int i = 0; i < MAX_FILTERSHADERS; i++) {
if (d3d->filterd3d->gfx_filtershader[i + MAX_FILTERSHADERS][0]) {
struct shaderdata *s = allocshaderslot (d3d, SHADERTYPE_AFTER);
if (!psEffect_LoadEffect (d3d, d3d->filterd3d->gfx_filtershader[i + MAX_FILTERSHADERS], true, s, i + MAX_FILTERSHADERS)) {
d3d->filterd3d->gfx_filtershader[i + MAX_FILTERSHADERS][0] = changed_prefs.gf[d3d->filterd3didx].gfx_filtershader[i + MAX_FILTERSHADERS][0] = 0;
break;
}
}
if (d3d->filterd3d->gfx_filtermask[i + MAX_FILTERSHADERS][0]) {
struct shaderdata *s = allocshaderslot (d3d, SHADERTYPE_MASK_AFTER);
createmasktexture (d3d, d3d->filterd3d->gfx_filtermask[i + MAX_FILTERSHADERS], s);
}
}
break;
}
if (d3d->filterd3d->gfx_filter_scanlines > 0) {
createsltexture(d3d);
createscanlines(d3d, 1);
}
if (wasshader && !shaderon)
write_log (_T("Falling back to non-shader mode\n"));
createmask2texture (d3d, d3d->filterd3d->gfx_filteroverlay);
createledtexture (d3d);
hr = D3DXCreateSprite (d3d->d3ddev, &d3d->sprite);
if (FAILED (hr)) {
write_log (_T("%s: D3DXSprite failed: %s\n"), D3DHEAD, D3D_ErrorString (hr));
}
int curw = CURSORMAXWIDTH, curh = CURSORMAXHEIGHT;
d3d->cursorsurfaced3d = createtext (d3d, curw, curh, D3DFMT_A8R8G8B8);
d3d->cursor_v = false;
d3d->cursor_scale = false;
vbsize = sizeof (struct TLVERTEX) * NUMVERTICES;
if (FAILED (hr = d3d->d3ddev->CreateVertexBuffer (vbsize, D3DUSAGE_WRITEONLY,
D3DFVF_TLVERTEX, D3DPOOL_DEFAULT, &d3d->vertexBuffer, NULL))) {
write_log (_T("%s: failed to create vertex buffer: %s\n"), D3DHEAD, D3D_ErrorString (hr));
return 0;
}
createvertex (d3d);
if (FAILED (hr = d3d->d3ddev->SetFVF (D3DFVF_TLVERTEX)))
write_log (_T("%s: SetFVF failed: %s\n"), D3DHEAD, D3D_ErrorString (hr));
if (FAILED (hr = d3d->d3ddev->SetStreamSource (0, d3d->vertexBuffer, 0, sizeof (struct TLVERTEX))))
write_log (_T("%s: SetStreamSource failed: %s\n"), D3DHEAD, D3D_ErrorString (hr));
hr = d3d->d3ddev->SetRenderState (D3DRS_CULLMODE, D3DCULL_NONE);
hr = d3d->d3ddev->SetRenderState (D3DRS_LIGHTING, FALSE);
settransform (d3d, NULL);
return 1;
}
static void D3D_free2 (struct d3dstruct *d3d)
{
invalidatedeviceobjects (d3d);
if (d3d->screenshotsurface)
d3d->screenshotsurface->Release();
d3d->screenshotsurface = NULL;
if (d3d->d3ddev) {
d3d->d3ddev->Release ();
d3d->d3ddev = NULL;
}
if (d3d->d3d) {
d3d->d3d->Release ();
d3d->d3d = NULL;
}
d3d->d3d_enabled = 0;
d3d->psActive = FALSE;
d3d->resetcount = 0;
d3d->devicelost = 0;
d3d->renderdisabled = false;
for (int i = 0; i < LED_MAX; i++) {
leds[i] = 0;
}
changed_prefs.leds_on_screen &= ~STATUSLINE_TARGET;
currprefs.leds_on_screen &= ~STATUSLINE_TARGET;
}
void xD3D_free (int monid, bool immediate)
{
struct d3dstruct *d3d = &d3ddata[monid];
if (!fakemodewaitms || immediate) {
waitfakemode (d3d);
D3D_free2 (d3d);
ddraw_fs_hack_free (d3d);
return;
}
}
#define VBLANKDEBUG 0
static bool xD3D_getvblankpos (int *vpos)
{
struct d3dstruct *d3d = &d3ddata[0];
HRESULT hr;
D3DRASTER_STATUS rt;
#if VBLANKDEBUG
static UINT lastline;
static BOOL lastinvblank;
#endif
*vpos = -2;
if (!isd3d (d3d))
return false;
if (d3d->d3dswapchain)
hr = d3d->d3dswapchain->GetRasterStatus (&rt);
else
hr = d3d->d3ddev->GetRasterStatus (0, &rt);
if (FAILED (hr)) {
write_log (_T("%s: GetRasterStatus %s\n"), D3DHEAD, D3D_ErrorString (hr));
return false;
}
if (rt.ScanLine > d3d->maxscanline)
d3d->maxscanline = rt.ScanLine;
*vpos = rt.ScanLine;
#if VBLANKDEBUG
if (lastline != rt.ScanLine || lastinvblank != rt.InVBlank) {
write_log(_T("%d:%d "), rt.InVBlank ? 1 : 0, rt.ScanLine);
lastline = rt.ScanLine;
lastinvblank = rt.InVBlank;
}
#endif
if (rt.InVBlank != 0)
*vpos = -1;
return true;
}
static void xD3D_vblank_reset (double freq)
{
struct d3dstruct *d3d = &d3ddata[0];
if (!isd3d (d3d))
return;
}
static int getd3dadapter (IDirect3D9 *id3d)
{
struct MultiDisplay *md = getdisplay(&currprefs, 0);
int num = id3d->GetAdapterCount ();
HMONITOR winmon;
POINT pt;
pt.x = (md->rect.right - md->rect.left) / 2 + md->rect.left;
pt.y = (md->rect.bottom - md->rect.top) / 2 + md->rect.top;
winmon = MonitorFromPoint (pt, MONITOR_DEFAULTTONEAREST);
for (int i = 0; i < num; i++) {
HMONITOR d3dmon = id3d->GetAdapterMonitor (i);
if (d3dmon == winmon)
return i;
}
return D3DADAPTER_DEFAULT;
}
static const TCHAR *D3D_init2 (struct d3dstruct *d3d, HWND ahwnd, int w_w, int w_h, int depth, int *freq, int mmulth, int mmultv)
{
int monid = d3d - d3ddata;
struct amigadisplay *ad = &adisplays[monid];
HRESULT ret, hr;
static TCHAR errmsg[300] = { 0 };
D3DDISPLAYMODE mode = { 0 };
D3DCAPS9 d3dCaps;
int adapter;
DWORD flags;
HINSTANCE d3dDLL, d3dx;
typedef HRESULT (WINAPI *LPDIRECT3DCREATE9EX)(UINT, IDirect3D9Ex**);
LPDIRECT3DCREATE9EX d3dexp = NULL;
int vsync = isvsync ();
struct apmode *apm = ad->picasso_on ? &currprefs.gfx_apmode[APMODE_RTG] : &currprefs.gfx_apmode[APMODE_NATIVE];
struct apmode ap;
D3DADAPTER_IDENTIFIER9 did;
d3d->filterd3didx = ad->picasso_on;
d3d->filterd3d = &currprefs.gf[d3d->filterd3didx];
D3D_free2 (d3d);
if (!currprefs.gfx_api) {
_tcscpy (errmsg, _T("D3D: not enabled"));
return errmsg;
}
xfree (d3d->fakebitmap);
d3d->fakebitmap = xmalloc (uae_u8, w_w * depth);
d3dx = LoadLibrary (D3DX9DLL);
if (d3dx == NULL) {
static bool warned;
if (!warned) {
if (os_vista)
_tcscpy(errmsg, _T("Direct3D: Optional DirectX9 components are not installed.\n")
_T("\nhttps://www.microsoft.com/en-us/download/details.aspx?id=8109"));
else
_tcscpy (errmsg, _T("Direct3D: Newer DirectX Runtime required or optional DirectX9 components are not installed.\n")
_T("\nhttps://www.microsoft.com/en-us/download/details.aspx?id=8109"));
warned = true;
}
return errmsg;
}
FreeLibrary (d3dx);
D3D_goodenough ();
D3D_canshaders ();
d3d->d3d_ex = FALSE;
d3dDLL = LoadLibrary (_T("D3D9.DLL"));
if (d3dDLL == NULL) {
_tcscpy (errmsg, _T("Direct3D: DirectX 9 or newer required"));
return errmsg;
} else {
d3dexp = (LPDIRECT3DCREATE9EX)GetProcAddress (d3dDLL, "Direct3DCreate9Ex");
if (d3dexp)
d3d->d3d_ex = TRUE;
}
FreeLibrary (d3dDLL);
hr = -1;
if (d3d->d3d_ex && D3DEX) {
hr = d3dexp (D3D_SDK_VERSION, &d3d->d3dex);
if (FAILED (hr))
write_log (_T("Direct3D: failed to create D3DEx object: %s\n"), D3D_ErrorString (hr));
d3d->d3d = (IDirect3D9*)d3d->d3dex;
}
if (FAILED (hr)) {
d3d->d3d_ex = 0;
d3d->d3dex = NULL;
d3d->d3d = Direct3DCreate9 (D3D_SDK_VERSION);
if (d3d->d3d == NULL) {
D3D_free(monid, true);
_tcscpy (errmsg, _T("Direct3D: failed to create D3D object"));
return errmsg;
}
}
if (d3d->d3d_ex)
D3DHEAD = _T("D3D9Ex");
else
D3DHEAD = _T("D3D9");
memcpy(&ap, apm, sizeof ap);
if (os_dwm_enabled && isfullscreen() <= 0 && apm->gfx_backbuffers > 1 && !apm->gfx_vsync) {
write_log(_T("Switch from triple buffer to double buffer (%d).\n"), apm->gfx_vflip);
ap.gfx_vflip = 0;
ap.gfx_backbuffers = 1;
}
adapter = getd3dadapter (d3d->d3d);
d3d->modeex.Size = sizeof d3d->modeex;
if (d3d->d3dex && D3DEX) {
LUID luid;
hr = d3d->d3dex->GetAdapterLUID (adapter, &luid);
hr = d3d->d3dex->GetAdapterDisplayModeEx (adapter, &d3d->modeex, NULL);
}
if (FAILED (hr = d3d->d3d->GetAdapterDisplayMode (adapter, &mode)))
write_log (_T("%s: GetAdapterDisplayMode failed %s\n"), D3DHEAD, D3D_ErrorString (hr));
if (FAILED (hr = d3d->d3d->GetDeviceCaps (adapter, D3DDEVTYPE_HAL, &d3dCaps)))
write_log (_T("%s: GetDeviceCaps failed %s\n"), D3DHEAD, D3D_ErrorString (hr));
if (SUCCEEDED (hr = d3d->d3d->GetAdapterIdentifier (adapter, 0, &did))) {
TCHAR *s = au (did.Description);
write_log (_T("Device name: '%s' %llx.%x\n"), s, did.DriverVersion, did.Revision);
xfree (s);
}
d3d->variablerefresh = false;
cannoclear = ap.gfx_vsyncmode != 0;
memset (&d3d->dpp, 0, sizeof (d3d->dpp));
d3d->dpp.Windowed = isfullscreen () <= 0;
d3d->dpp.BackBufferFormat = mode.Format;
d3d->dpp.BackBufferCount = ap.gfx_backbuffers;
d3d->dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3d->dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
d3d->dpp.BackBufferWidth = w_w;
d3d->dpp.BackBufferHeight = w_h;
d3d->dpp.PresentationInterval = d3d->variablerefresh ? D3DPRESENT_INTERVAL_DEFAULT : ((!ap.gfx_vflip || monid) ? D3DPRESENT_INTERVAL_IMMEDIATE : D3DPRESENT_INTERVAL_ONE);
d3d->modeex.Width = w_w;
d3d->modeex.Height = w_h;
d3d->modeex.RefreshRate = 0;
d3d->modeex.ScanLineOrdering = ap.gfx_interlaced ? D3DSCANLINEORDERING_INTERLACED : D3DSCANLINEORDERING_PROGRESSIVE;
d3d->modeex.Format = mode.Format;
d3d->vsync2 = 0;
int hzmult = 0;
if (isfullscreen () > 0) {
d3d->dpp.FullScreen_RefreshRateInHz = getrefreshrate(monid, d3d->modeex.Width, d3d->modeex.Height);
d3d->modeex.RefreshRate = d3d->dpp.FullScreen_RefreshRateInHz;
if (vsync > 0) {
d3d->dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
getvsyncrate(monid, d3d->dpp.FullScreen_RefreshRateInHz, &hzmult);
if (hzmult < 0) {
if (!ap.gfx_strobo) {
if (d3dCaps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO)
d3d->dpp.PresentationInterval = D3DPRESENT_INTERVAL_TWO;
} else {
d3d->vsync2 = -2;
}
} else if (hzmult > 0) {
d3d->vsync2 = 1;
}
}
*freq = d3d->modeex.RefreshRate;
} else {
if (mode.RefreshRate > 0) {
if (vsync > 0) {
d3d->dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
getvsyncrate(monid, mode.RefreshRate, &hzmult);
if (hzmult < 0) {
if (!ap.gfx_strobo) {
if ((d3dCaps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO) && isfullscreen() > 0)
d3d->dpp.PresentationInterval = D3DPRESENT_INTERVAL_TWO;
} else {
d3d->vsync2 = -2;
}
} else if (hzmult > 0) {
d3d->vsync2 = 1;
}
}
*freq = mode.RefreshRate;
}
}
if (vsync < 0) {
d3d->vsync2 = 0;
getvsyncrate(monid, isfullscreen() > 0 ? d3d->dpp.FullScreen_RefreshRateInHz : mode.RefreshRate, &hzmult);
if (hzmult > 0) {
d3d->vsync2 = 1;
} else if (hzmult < 0) {
if (ap.gfx_strobo) {
d3d->vsync2 = -2;
} else if (ap.gfx_vflip) {
if ((d3dCaps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO) && isfullscreen() > 0)
d3d->dpp.PresentationInterval = D3DPRESENT_INTERVAL_TWO;
else
d3d->vsync2 = -1;
}
}
}
d3d->d3dhwnd = ahwnd;
d3d->t_depth = depth;
flags = D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED;
// Check if hardware vertex processing is available
if(d3dCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {
flags |= D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE;
} else {
flags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}
if (d3d->d3d_ex && D3DEX) {
ret = d3d->d3dex->CreateDeviceEx (adapter, D3DDEVTYPE_HAL, d3d->d3dhwnd, flags, &d3d->dpp, d3d->dpp.Windowed ? NULL : &d3d->modeex, &d3d->d3ddevex);
d3d->d3ddev = d3d->d3ddevex;
} else {
ret = d3d->d3d->CreateDevice (adapter, D3DDEVTYPE_HAL, d3d->d3dhwnd, flags, &d3d->dpp, &d3d->d3ddev);
}
if (FAILED (ret) && (flags & D3DCREATE_PUREDEVICE)) {
flags &= ~D3DCREATE_PUREDEVICE;
if (d3d->d3d_ex && D3DEX) {
ret = d3d->d3dex->CreateDeviceEx (adapter, D3DDEVTYPE_HAL, d3d->d3dhwnd, flags, &d3d->dpp, d3d->dpp.Windowed ? NULL : &d3d->modeex, &d3d->d3ddevex);
d3d->d3ddev = d3d->d3ddevex;
} else {
ret = d3d->d3d->CreateDevice (adapter, D3DDEVTYPE_HAL, d3d->d3dhwnd, flags, &d3d->dpp, &d3d->d3ddev);
}
if (FAILED (ret) && (flags & D3DCREATE_HARDWARE_VERTEXPROCESSING)) {
flags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;
flags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
if (d3d->d3d_ex && D3DEX) {
ret = d3d->d3dex->CreateDeviceEx (adapter, D3DDEVTYPE_HAL, d3d->d3dhwnd, flags, &d3d->dpp, d3d->dpp.Windowed ? NULL : &d3d->modeex, &d3d->d3ddevex);
d3d->d3ddev = d3d->d3ddevex;
} else {
ret = d3d->d3d->CreateDevice (adapter, D3DDEVTYPE_HAL, d3d->d3dhwnd, flags, &d3d->dpp, &d3d->d3ddev);
}
}
}
if (FAILED (ret)) {
_stprintf (errmsg, _T("%s failed, %s\n"), d3d->d3d_ex && D3DEX ? _T("CreateDeviceEx") : _T("CreateDevice"), D3D_ErrorString (ret));
if (ret == D3DERR_INVALIDCALL && d3d->dpp.Windowed == 0 && d3d->dpp.FullScreen_RefreshRateInHz && !d3d->ddraw_fs) {
write_log (_T("%s\n"), errmsg);
write_log (_T("%s: Retrying fullscreen with DirectDraw\n"), D3DHEAD);
if (ddraw_fs_hack_init (d3d)) {
const TCHAR *err2 = D3D_init (ahwnd, monid, w_w, w_h, depth, freq, mmulth, mmultv);
if (err2)
ddraw_fs_hack_free (d3d);
return err2;
}
}
if (d3d->d3d_ex && D3DEX) {
write_log (_T("%s\n"), errmsg);
D3DEX = 0;
return D3D_init(ahwnd, monid, w_w, w_h, depth, freq, mmulth, mmultv);
}
D3D_free(monid, true);
return errmsg;
}
if (d3dCaps.PixelShaderVersion >= D3DPS_VERSION(2, 0))
d3d->psEnabled = TRUE;
else
d3d->psEnabled = FALSE;
d3d->max_texture_w = d3dCaps.MaxTextureWidth;
d3d->max_texture_h = d3dCaps.MaxTextureHeight;
write_log (_T("%s: %08X %08X %08X %08X"), D3DHEAD, flags, d3dCaps.Caps, d3dCaps.Caps2, d3dCaps.Caps3);
if (d3dCaps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY)
write_log (_T(" SQUAREONLY"));
if (d3dCaps.TextureCaps & D3DPTEXTURECAPS_POW2)
write_log (_T(" POW2"));
if (d3dCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL)
write_log (_T(" NPOTCONDITIONAL"));
if (d3dCaps.TextureCaps & D3DPTEXTURECAPS_ALPHA)
write_log (_T(" ALPHA"));
if (d3dCaps.Caps2 & D3DCAPS2_DYNAMICTEXTURES)
write_log (_T(" DYNAMIC"));
if (d3dCaps.Caps & D3DCAPS_READ_SCANLINE)
write_log (_T(" SCANLINE"));
write_log (_T("\n"));
write_log (_T("%s: PS=%d.%d VS=%d.%d %d*%d*%d%s%s VS=%d B=%d%s %d-bit %d (%dx%d)\n"),
D3DHEAD,
(d3dCaps.PixelShaderVersion >> 8) & 0xff, d3dCaps.PixelShaderVersion & 0xff,
(d3dCaps.VertexShaderVersion >> 8) & 0xff, d3dCaps.VertexShaderVersion & 0xff,
d3d->modeex.Width, d3d->modeex.Height,
d3d->dpp.FullScreen_RefreshRateInHz,
ap.gfx_interlaced ? _T("i") : _T("p"),
d3d->dpp.Windowed ? _T("") : _T(" FS"),
vsync, ap.gfx_backbuffers,
ap.gfx_vflip < 0 ? _T("WE") : (ap.gfx_vflip > 0 ? _T("WS") : _T("I")),
d3d->t_depth, adapter,
d3d->max_texture_w, d3d->max_texture_h
);
#if 0
if ((d3dCaps.PixelShaderVersion < D3DPS_VERSION(2,0) || !d3d->psEnabled || d3d->max_texture_w < 2048 || d3d->max_texture_h < 2048 || (!shaderon && SHADER > 0)) && d3d->d3d_ex) {
D3DEX = 0;
write_log (_T("Disabling D3D9Ex\n"));
if (d3d->d3ddev) {
d3d->d3ddev->Release ();
d3d->d3ddev = NULL;
}
if (d3d->d3d) {
d3d->d3d->Release ();
d3d->d3d = NULL;
}
d3d->d3ddevex = NULL;
return D3D_init (ahwnd, w_w, w_h, depth, freq, mmult);
}
#endif
if (!shaderon)
write_log (_T("Using non-shader version\n"));
d3d->dmultxh = mmulth;
d3d->dmultxv = mmultv;
d3d->dmult = S2X_getmult(d3d - d3ddata);
d3d->window_w = w_w;
d3d->window_h = w_h;
if (d3d->max_texture_w < w_w || d3d->max_texture_h < w_h) {
_stprintf (errmsg, _T("%s: %d * %d or bigger texture support required\nYour card's maximum texture size is only %d * %d"),
D3DHEAD, w_w, w_h, d3d->max_texture_w, d3d->max_texture_h);
return errmsg;
}
while (d3d->dmultxh > 1 && w_w * d3d->dmultxh > d3d->max_texture_w)
d3d->dmultxh--;
while (d3d->dmultxv > 1 && w_h * d3d->dmultxv > d3d->max_texture_h)
d3d->dmultxv--;
d3d->required_sl_texture_w = w_w;
d3d->required_sl_texture_h = w_h;
if (d3d->filterd3d->gfx_filter_scanlines > 0 && (d3d->max_texture_w < w_w || d3d->max_texture_h < w_h)) {
gui_message (_T("%s: %d * %d or bigger texture support required for scanlines (max is only %d * %d)\n"),
D3DHEAD, _T("Scanlines disabled."),
d3d->required_sl_texture_w, d3d->required_sl_texture_h, d3d->max_texture_w, d3d->max_texture_h);
changed_prefs.gf[d3d->filterd3didx].gfx_filter_scanlines = d3d->filterd3d->gfx_filter_scanlines = 0;
}
switch (depth)
{
case 32:
default:
d3d->tformat = D3DFMT_X8R8G8B8;
break;
case 15:
d3d->tformat = D3DFMT_X1R5G5B5;
break;
case 16:
d3d->tformat = D3DFMT_R5G6B5;
break;
}
changed_prefs.leds_on_screen |= STATUSLINE_TARGET;
currprefs.leds_on_screen |= STATUSLINE_TARGET;
if (!restoredeviceobjects (d3d)) {
D3D_free(monid, true);
_stprintf (errmsg, _T("%s: initialization failed."), D3DHEAD);
return errmsg;
}
d3d->maxscanline = 0;
d3d->d3d_enabled = 1;
d3d->wasstilldrawing_broken = true;
if ((vsync < 0 || d3d->variablerefresh) && ap.gfx_vflip == 0) {
hr = d3d->d3ddev->CreateQuery(D3DQUERYTYPE_EVENT, &d3d->query);
if (FAILED (hr))
write_log (_T("%s: CreateQuery(D3DQUERYTYPE_EVENT) failed: %s\n"), D3DHEAD, D3D_ErrorString (hr));
}
if (d3d->d3ddevex) {
UINT v = 12345;
hr = d3d->d3ddevex->GetMaximumFrameLatency (&v);
if (FAILED (hr)) {
write_log (_T("%s: GetMaximumFrameLatency() failed: %s\n"), D3DHEAD, D3D_ErrorString (hr));
v = 1;
}
hr = S_OK;
if (forcedframelatency >= 0) {
hr = d3d->d3ddevex->SetMaximumFrameLatency(forcedframelatency);
} else if (ap.gfx_vsyncmode) {
hr = d3d->d3ddevex->SetMaximumFrameLatency(1);
} else if (d3d->dpp.PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE && (v > 1 || !vsync)) {
hr = d3d->d3ddevex->SetMaximumFrameLatency((vsync || d3d->variablerefresh) ? (hzmult < 0 && !ap.gfx_strobo && !d3d->variablerefresh ? 2 : 1) : 0);
}
if (FAILED (hr))
write_log (_T("%s: SetMaximumFrameLatency() failed: %s\n"), D3DHEAD, D3D_ErrorString (hr));
}
hr = d3d->d3ddev->CreateOffscreenPlainSurface(w_w, w_h, d3d->tformat, D3DPOOL_SYSTEMMEM, &d3d->screenshotsurface, NULL);
if (FAILED(hr)) {
write_log(_T("%s: CreateOffscreenPlainSurface RT failed: %s\n"), D3DHEAD, D3D_ErrorString(hr));
}
return 0;
}
struct d3d_initargs
{
HWND hwnd;
int w;
int h;
int depth;
int mmulth, mmultv;
int *freq;
};
static struct d3d_initargs d3dargs;
static void D3D_init_start (void *p)
{
struct d3dstruct *d3d = &d3ddata[0];
struct timeval tv1, tv2;
gettimeofday (&tv1, NULL);
sleep_millis (1000);
write_log (_T("Threaded D3D_init() start (free)\n"));
D3D_free2 (d3d);
sleep_millis (1000);
write_log (_T("Threaded D3D_init() start (init)\n"));
const TCHAR *t = D3D_init2 (d3d, d3dargs.hwnd, d3dargs.w, d3dargs.h,d3dargs.depth, d3dargs.freq, d3dargs.mmulth, d3dargs.mmultv);
if (t) {
gui_message (_T("Threaded D3D_init() returned error '%s'\n"), t);
}
write_log (_T("Threaded D3D_init() returned\n"));
for (;;) {
uae_u64 us1, us2, diff;
gettimeofday (&tv2, NULL);
us1 = (uae_u64)tv1.tv_sec * 1000000 + tv1.tv_usec;
us2 = (uae_u64)tv2.tv_sec * 1000000 + tv2.tv_usec;
diff = us2 - us1;
if (diff >= fakemodewaitms * 1000)
break;
sleep_millis (10);
}
write_log (_T("Threaded D3D_init() finished\n"));
d3d->frames_since_init = 0;
d3d->fakemode = false;
}
static const TCHAR *xD3D_init (HWND ahwnd, int monid, int w_w, int w_h, int depth, int *freq, int mmulth, int mmultv)
{
struct d3dstruct *d3d = &d3ddata[monid];
if (!fakemodewaitms)
return D3D_init2 (d3d, ahwnd, w_w, w_h, depth, freq, mmulth, mmultv);
d3d->fakemode = true;
d3dargs.hwnd = ahwnd;
d3dargs.w = w_w;
d3dargs.h = w_h;
d3dargs.depth = depth;
d3dargs.mmulth = mmulth;
d3dargs.mmultv = mmultv;
d3dargs.freq = freq;
uae_start_thread_fast (D3D_init_start, NULL, &d3d->fakemodetid);
return NULL;
}
static bool alloctextures (struct d3dstruct *d3d)
{
if (!createtexture (d3d, d3d->tout_w, d3d->tout_h, d3d->window_w, d3d->window_h))
return false;
if (!createamigatexture (d3d, d3d->tin_w, d3d->tin_h))
return false;
return true;
}
static bool xD3D_alloctexture (int monid, int w, int h)
{
struct d3dstruct *d3d = &d3ddata[monid];
d3d->tin_w = w * d3d->dmult;
d3d->tin_h = h * d3d->dmult;
d3d->tout_w = d3d->tin_w * d3d->dmultxh;
d3d->tout_h = d3d->tin_h * d3d->dmultxv;
if (d3d->fakemode)
return false;
changed_prefs.leds_on_screen |= STATUSLINE_TARGET;
currprefs.leds_on_screen |= STATUSLINE_TARGET;
freetextures (d3d);
return alloctextures (d3d);
}
static HRESULT reset (void)
{
struct d3dstruct *d3d = &d3ddata[0];
HRESULT hr;
bool oldrender = d3d->renderdisabled;
d3d->renderdisabled = true;
if (d3d->d3dex)
hr = d3d->d3ddevex->ResetEx (&d3d->dpp, d3d->dpp.Windowed ? NULL : &d3d->modeex);
else
hr = d3d->d3ddev->Reset (&d3d->dpp);
d3d->renderdisabled = oldrender;
return hr;
}
static int D3D_needreset (struct d3dstruct *d3d)
{
HRESULT hr;
bool do_dd = false;
if (!d3d->devicelost)
return -1;
if (d3d->d3dex)
hr = d3d->d3ddevex->CheckDeviceState (d3d->d3dhwnd);
else
hr = d3d->d3ddev->TestCooperativeLevel ();
if (hr == S_PRESENT_OCCLUDED) {
// no need to draw anything
return 1;
}
if (hr == D3DERR_DEVICELOST) {
d3d->renderdisabled = true;
// lost but can't be reset yet
return 1;
}
if (hr == D3DERR_DEVICENOTRESET) {
// lost and can be reset
write_log (_T("%s: DEVICENOTRESET\n"), D3DHEAD);
d3d->devicelost = 2;
invalidatedeviceobjects (d3d);
freetextures (d3d);
hr = reset ();
if (FAILED (hr)) {
write_log (_T("%s: Reset failed %s\n"), D3DHEAD, D3D_ErrorString (hr));
d3d->resetcount++;
if (d3d->resetcount > 2 || hr == D3DERR_DEVICEHUNG) {
changed_prefs.gfx_api = 0;
write_log (_T("%s: Too many failed resets, disabling Direct3D mode\n"), D3DHEAD);
}
return 1;
}
d3d->devicelost = 0;
write_log (_T("%s: Reset succeeded\n"), D3DHEAD);
d3d->renderdisabled = false;
restoredeviceobjects (d3d);
alloctextures (d3d);
return -1;
} else if (hr == S_PRESENT_MODE_CHANGED) {
write_log (_T("%s: S_PRESENT_MODE_CHANGED (%d,%d)\n"), D3DHEAD, d3d->ddraw_fs, d3d->ddraw_fs_attempt);
#if 0
if (!d3d->ddraw_fs) {
d3d->ddraw_fs_attempt++;
if (d3d->ddraw_fs_attempt >= 5) {
do_dd = true;
}
}
#endif
}
if (SUCCEEDED (hr)) {
d3d->devicelost = 0;
invalidatedeviceobjects (d3d);
if (do_dd) {
write_log (_T("%s: S_PRESENT_MODE_CHANGED, Retrying fullscreen with DirectDraw\n"), D3DHEAD);
ddraw_fs_hack_init (d3d);
}
hr = reset ();
if (FAILED (hr))
write_log (_T("%s: Reset failed %s\n"), D3DHEAD, D3D_ErrorString (hr));
restoredeviceobjects (d3d);
return -1;
}
write_log (_T("%s: TestCooperativeLevel %s\n"), D3DHEAD, D3D_ErrorString (hr));
return 0;
}
static void D3D_showframe2 (struct d3dstruct *d3d, bool dowait)
{
HRESULT hr;
if (!isd3d (d3d))
return;
for (;;) {
if (d3d->d3dswapchain)
hr = d3d->d3dswapchain->Present (NULL, NULL, NULL, NULL, dowait ? 0 : D3DPRESENT_DONOTWAIT);
else
hr = d3d->d3ddev->Present (NULL, NULL, NULL, NULL);
if (hr == D3DERR_WASSTILLDRAWING) {
d3d->wasstilldrawing_broken = false;
if (!dowait)
return;
sleep_millis (1);
continue;
} else if (hr == S_PRESENT_OCCLUDED) {
d3d->renderdisabled = true;
} else if (hr == S_PRESENT_MODE_CHANGED) {
// In most cases mode actually didn't change but
// D3D is just being stupid and not accepting
// all modes that DirectDraw does accept,
// for example interlaced or EDS_RAWMODE modes!
//devicelost = 1;
; //write_log (_T("S_PRESENT_MODE_CHANGED\n"));
} else if (FAILED (hr)) {
write_log (_T("%s: Present() %s\n"), D3DHEAD, D3D_ErrorString (hr));
if (hr == D3DERR_DEVICELOST || hr == S_PRESENT_MODE_CHANGED) {
d3d->devicelost = 1;
d3d->renderdisabled = true;
write_log (_T("%s: mode changed or fullscreen focus lost\n"), D3DHEAD);
}
} else {
d3d->ddraw_fs_attempt = 0;
}
return;
}
}
static void xD3D_restore(int monid, bool checkonly)
{
struct d3dstruct *d3d = &d3ddata[monid];
if (checkonly)
return;
d3d->renderdisabled = false;
}
static void xD3D_clear (int monid)
{
struct d3dstruct *d3d = &d3ddata[monid];
int i;
HRESULT hr;
if (!isd3d (d3d))
return;
for (i = 0; i < 2; i++) {
hr = d3d->d3ddev->Clear (0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, d3ddebug ? 0x80 : 0x00), 0, 0);
D3D_showframe2 (d3d, true);
}
}
static LPDIRECT3DTEXTURE9 processshader(struct d3dstruct *d3d, LPDIRECT3DTEXTURE9 srctex, struct shaderdata *s, bool rendertarget)
{
HRESULT hr;
UINT uPasses, uPass;
LPDIRECT3DSURFACE9 lpRenderTarget;
LPDIRECT3DSURFACE9 lpNewRenderTarget;
LPDIRECT3DTEXTURE9 lpWorkTexture;
if (!psEffect_SetTextures (srctex, s))
return NULL;
if (s->psPreProcess) {
if (!psEffect_SetMatrices (&d3d->m_matPreProj, &d3d->m_matPreView, &d3d->m_matPreWorld, s))
return NULL;
if (FAILED (hr = d3d->d3ddev->GetRenderTarget (0, &lpRenderTarget)))
write_log (_T("%s: GetRenderTarget: %s\n"), D3DHEAD, D3D_ErrorString (hr));
lpWorkTexture = s->lpWorkTexture1;
lpNewRenderTarget = NULL;
pass2:
if (FAILED (hr = lpWorkTexture->GetSurfaceLevel (0, &lpNewRenderTarget)))
write_log (_T("%s: GetSurfaceLevel: %s\n"), D3DHEAD, D3D_ErrorString (hr));
if (FAILED (hr = d3d->d3ddev->SetRenderTarget (0, lpNewRenderTarget)))
write_log (_T("%s: SetRenderTarget: %s\n"), D3DHEAD, D3D_ErrorString (hr));
uPasses = 0;
if (psEffect_Begin ((lpWorkTexture == s->lpWorkTexture1) ? psEffect_PreProcess1 : psEffect_PreProcess2, &uPasses, s)) {
for (uPass = 0; uPass < uPasses; uPass++) {
if (psEffect_BeginPass (s->pEffect, uPass)) {
if (FAILED (hr = d3d->d3ddev->DrawPrimitive (D3DPT_TRIANGLESTRIP, 4, 2))) {
write_log (_T("%s: Effect DrawPrimitive failed: %s\n"), D3DHEAD, D3D_ErrorString (hr));
}
psEffect_EndPass (s->pEffect);
}
}
psEffect_End (s->pEffect);
}
if (FAILED (hr = d3d->d3ddev->SetRenderTarget (0, lpRenderTarget)))
write_log (_T("%s: Effect RenderTarget reset failed: %s\n"), D3DHEAD, D3D_ErrorString (hr));
lpNewRenderTarget->Release ();
lpNewRenderTarget = NULL;
if (psEffect_hasPreProcess2 (s) && lpWorkTexture == s->lpWorkTexture1) {
lpWorkTexture = s->lpWorkTexture2;
goto pass2;
}
lpRenderTarget->Release ();
lpRenderTarget = NULL;
}
psEffect_SetMatrices (&d3d->m_matProj2, &d3d->m_matView2, &d3d->m_matWorld2, s);
if (rendertarget) {
#if TWOPASS
if (FAILED (hr = d3d->d3ddev->GetRenderTarget (0, &lpRenderTarget)))
write_log (_T("%s: GetRenderTarget: %s\n"), D3DHEAD, D3D_ErrorString (hr));
if (FAILED (hr = s->lpTempTexture->GetSurfaceLevel (0, &lpNewRenderTarget)))
write_log (_T("%s: GetSurfaceLevel: %s\n"), D3DHEAD, D3D_ErrorString (hr));
if (FAILED (hr = d3d->d3ddev->SetRenderTarget (0, lpNewRenderTarget)))
write_log (_T("%s: SetRenderTarget: %s\n"), D3DHEAD, D3D_ErrorString (hr));
#endif
}
uPasses = 0;
if (psEffect_Begin (psEffect_Combine, &uPasses, s)) {
for (uPass = 0; uPass < uPasses; uPass++) {
if (!psEffect_BeginPass (s->pEffect, uPass))
return NULL;
if (FAILED (hr = d3d->d3ddev->DrawPrimitive (D3DPT_TRIANGLESTRIP, 0, 2)))
write_log (_T("%s: Effect2 DrawPrimitive failed: %s\n"), D3DHEAD, D3D_ErrorString (hr));
psEffect_EndPass (s->pEffect);
}
psEffect_End (s->pEffect);
}
if (rendertarget) {
#if TWOPASS
if (FAILED (hr = d3d->d3ddev->SetRenderTarget (0, lpRenderTarget)))
write_log (_T("%s: SetRenderTarget: %s\n"), D3DHEAD, D3D_ErrorString (hr));
lpNewRenderTarget->Release ();
lpRenderTarget->Release ();
#endif
}
return s->lpTempTexture;
}
static void xD3D_led(int led, int on, int brightness)
{
struct d3dstruct *d3d = &d3ddata[0];
leds[led] = on;
}
static int xD3D_debug(int monid, int mode)
{
struct d3dstruct *d3d = &d3ddata[monid];
int old = debugcolors ? 1 : 0;
debugcolors = (mode & 1) != 0;
noclear = debugcolors ? false : true;
clearcnt = 0;
return old;
}
static void clearrt(struct d3dstruct *d3d)
{
HRESULT hr;
uae_u8 color[4] = { 0, 0, 0, 0 };
if (noclear && cannoclear) {
if (clearcnt > 3)
return;
clearcnt++;
}
if (!noclear && debugcolors && slicecnt > 0) {
int cnt = slicecnt - 1;
int v = cnt % 3;
if (cnt / 3 == 1)
color[(v + 1) % 3] = 80;
color[v] = 80;
}
hr = d3d->d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(color[0], d3ddebug ? 0x80 : color[1], color[2]), 0, 0);
}
static void D3D_render2(struct d3dstruct *d3d, int mode)
{
struct AmigaMonitor *mon = &AMonitors[d3d - d3ddata];
HRESULT hr;
LPDIRECT3DTEXTURE9 srctex = d3d->texture;
UINT uPasses, uPass;
if (!isd3d (d3d) || !d3d->texture)
return;
bool normalrender = mode < 0 || (mode & 1);
if (mode > 0 && (mode & 2))
slicecnt = 0;
else if (mode < 0)
slicecnt = slicecnt == 2 ? 0 : slicecnt;
clearrt(d3d);
slicecnt++;
if (FAILED (hr = d3d->d3ddev->BeginScene ())) {
write_log (_T("%s: BeginScene: %s\n"), D3DHEAD, D3D_ErrorString (hr));
return;
}
if (shaderon > 0 && d3d->shaders[SHADER_POST].pEffect) {
for (int i = 0; i < MAX_SHADERS; i++) {
struct shaderdata *s = &d3d->shaders[i];
if (s->type == SHADERTYPE_BEFORE)
settransform_pre (d3d, s);
if (s->type == SHADERTYPE_MIDDLE) {
d3d->m_matProj = d3d->m_matProj_out;
d3d->m_matView = d3d->m_matView_out;
d3d->m_matWorld = d3d->m_matWorld_out;
}
if (s->type == SHADERTYPE_BEFORE || s->type == SHADERTYPE_MIDDLE) {
settransform (d3d, s);
srctex = processshader (d3d, srctex, s, true);
if (!srctex)
return;
}
}
}
d3d->m_matProj = d3d->m_matProj_out;
d3d->m_matView = d3d->m_matView_out;
d3d->m_matWorld = d3d->m_matWorld_out;
#if TWOPASS
if (shaderon > 0 && d3d->shaders[SHADER_POST].pEffect) {
LPDIRECT3DSURFACE9 lpRenderTarget;
LPDIRECT3DSURFACE9 lpNewRenderTarget;
struct shaderdata *s = &d3d->shaders[SHADER_POST];
LPD3DXEFFECT postEffect = s->pEffect;
int after = -1;
LPDIRECT3DTEXTURE9 masktexture = NULL;
D3DSURFACE_DESC Desc;
D3DXVECTOR4 texelsize;
for (int i = 0; i < MAX_SHADERS; i++) {
struct shaderdata *s = &d3d->shaders[i];
if (s->type == SHADERTYPE_AFTER)
after = i;
if (s->type == SHADERTYPE_MASK_MIDDLE && s->masktexture)
masktexture = s->masktexture;
}
setupscenecoords(d3d, normalrender);
hr = d3d->d3ddev->SetTransform (D3DTS_PROJECTION, &d3d->m_matProj);
hr = d3d->d3ddev->SetTransform (D3DTS_VIEW, &d3d->m_matView);
hr = d3d->d3ddev->SetTransform (D3DTS_WORLD, &d3d->m_matWorld);
hr = postEffect->SetMatrix (d3d->postMatrixSource, &d3d->postproj);
hr = postEffect->SetVector (d3d->postMaskMult, &d3d->maskmult);
hr = postEffect->SetVector (d3d->postMaskShift, &d3d->maskshift);
srctex->GetLevelDesc (0, &Desc);
texelsize.x = 1.0f / Desc.Width;
texelsize.y = 1.0f / Desc.Height;
texelsize.z = 1; texelsize.w = 1;
hr = postEffect->SetVector (d3d->postTexelSize, &texelsize);
if (d3d->postFramecounterHandle)
postEffect->SetFloat(d3d->postFramecounterHandle, timeframes);
if (masktexture) {
if (FAILED (hr = postEffect->SetTechnique (d3d->postTechnique)))
write_log (_T("%s: SetTechnique(postTechnique) failed: %s\n"), D3DHEAD, D3D_ErrorString (hr));
if (FAILED (hr = postEffect->SetTexture (d3d->postMaskTextureHandle, masktexture)))
write_log (_T("%s: SetTexture(masktexture) failed: %s\n"), D3DHEAD, D3D_ErrorString (hr));
} else if (d3d->sltexture) {
if (FAILED (hr = postEffect->SetTechnique (d3d->postTechniqueAlpha)))
write_log (_T("%s: SetTechnique(postTechniqueAlpha) failed: %s\n"), D3DHEAD, D3D_ErrorString (hr));
if (FAILED (hr = postEffect->SetTexture (d3d->postMaskTextureHandle, d3d->sltexture)))
write_log (_T("%s: SetTexture(sltexture) failed: %s\n"), D3DHEAD, D3D_ErrorString (hr));
} else {
if (FAILED (hr = postEffect->SetTechnique (d3d->postTechniquePlain)))
write_log (_T("%s: SetTechnique(postTechniquePlain) failed: %s\n"), D3DHEAD, D3D_ErrorString (hr));
}
hr = postEffect->SetInt (d3d->postFilterMode, d3d->filterd3d->gfx_filter_bilinear ? D3DTEXF_LINEAR : D3DTEXF_POINT);
if (FAILED (hr = postEffect->SetTexture (d3d->postSourceTextureHandle, srctex)))
write_log (_T("%s: SetTexture(srctex) failed: %s\n"), D3DHEAD, D3D_ErrorString (hr));
if (s->m_SourceDimsEffectHandle) {
D3DXVECTOR4 fDimsSource;
fDimsSource.x = (FLOAT)Desc.Width;
fDimsSource.y = (FLOAT)Desc.Height;
fDimsSource.z = 1; fDimsSource.w = 1;
hr = postEffect->SetVector(s->m_SourceDimsEffectHandle, &fDimsSource);
if (FAILED(hr)) {
write_log(_T("%s: SetTextures:SetVector:Source %s\n"), D3DHEAD, D3D_ErrorString(hr));
}
}
if (s->m_TargetDimsEffectHandle) {
D3DXVECTOR4 fDimsTarget;
fDimsTarget.x = s->targettex_width;
fDimsTarget.y = s->targettex_height;
fDimsTarget.z = 1; fDimsTarget.w = 1;
hr = postEffect->SetVector(s->m_TargetDimsEffectHandle, &fDimsTarget);
if (FAILED(hr)) {
write_log(_T("%s: SetTextures:SetVector:Target %s\n"), D3DHEAD, D3D_ErrorString(hr));
}
}
if (after >= 0) {
if (FAILED (hr = d3d->d3ddev->GetRenderTarget (0, &lpRenderTarget)))
write_log (_T("%s: GetRenderTarget: %s\n"), D3DHEAD, D3D_ErrorString (hr));
if (FAILED (hr = d3d->lpPostTempTexture->GetSurfaceLevel (0, &lpNewRenderTarget)))
write_log (_T("%s: GetSurfaceLevel: %s\n"), D3DHEAD, D3D_ErrorString (hr));
if (FAILED (hr = d3d->d3ddev->SetRenderTarget (0, lpNewRenderTarget)))
write_log (_T("%s: SetRenderTarget: %s\n"), D3DHEAD, D3D_ErrorString (hr));
}
uPasses = 0;
if (psEffect_Begin (psEffect_None, &uPasses, s)) {
for (uPass = 0; uPass < uPasses; uPass++) {
if (psEffect_BeginPass (postEffect, uPass)) {
if (FAILED (hr = d3d->d3ddev->DrawPrimitive (D3DPT_TRIANGLESTRIP, 0, 2)))
write_log (_T("%s: Post DrawPrimitive failed: %s\n"), D3DHEAD, D3D_ErrorString (hr));
psEffect_EndPass (postEffect);
}
}
psEffect_End (postEffect);
}
if (after >= 0) {
if (FAILED (hr = d3d->d3ddev->SetRenderTarget (0, lpRenderTarget)))
write_log (_T("%s: SetRenderTarget: %s\n"), D3DHEAD, D3D_ErrorString (hr));
lpNewRenderTarget->Release ();
lpRenderTarget->Release ();
srctex = d3d->lpPostTempTexture;
for (int i = 0; i < MAX_SHADERS; i++) {
struct shaderdata *s = &d3d->shaders[i];
if (s->type == SHADERTYPE_AFTER) {
settransform2 (d3d, s);
srctex = processshader (d3d, srctex, s, i != after);
if (!srctex)
return;
}
}
}
} else {
// non-shader version
setupscenecoords (d3d, normalrender);
hr = d3d->d3ddev->SetTransform (D3DTS_PROJECTION, &d3d->m_matProj);
hr = d3d->d3ddev->SetTransform (D3DTS_VIEW, &d3d->m_matView);
hr = d3d->d3ddev->SetTransform (D3DTS_WORLD, &d3d->m_matWorld);
hr = d3d->d3ddev->SetTexture (0, srctex);
hr = d3d->d3ddev->DrawPrimitive (D3DPT_TRIANGLESTRIP, 0, 2);
int bl = d3d->filterd3d->gfx_filter_bilinear ? D3DTEXF_LINEAR : D3DTEXF_POINT;
hr = d3d->d3ddev->SetSamplerState(0, D3DSAMP_MINFILTER, bl);
hr = d3d->d3ddev->SetSamplerState(0, D3DSAMP_MAGFILTER, bl);
hr = d3d->d3ddev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
hr = d3d->d3ddev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
if (d3d->sprite && d3d->sltexture) {
D3DXVECTOR3 v;
d3d->sprite->Begin(D3DXSPRITE_ALPHABLEND);
v.x = v.y = v.z = 0;
d3d->sprite->Draw(d3d->sltexture, NULL, NULL, &v, 0xffffffff);
d3d->sprite->End();
}
}
if (d3d->sprite && ((d3d->ledtexture) || (d3d->mask2texture) || (d3d->cursorsurfaced3d && d3d->cursor_v))) {
D3DXVECTOR3 v;
d3d->sprite->Begin(D3DXSPRITE_ALPHABLEND);
if (d3d->cursorsurfaced3d && d3d->cursor_v) {
D3DXMATRIXA16 t;
if (d3d->cursor_scale)
MatrixScaling(&t, ((float)(d3d->window_w) / (d3d->tout_w + 2 * d3d->cursor_offset2_x)), ((float)(d3d->window_h) / (d3d->tout_h + 2 * d3d->cursor_offset2_y)), 0);
else
MatrixScaling(&t, 1.0f, 1.0f, 0);
v.x = d3d->cursor_x + d3d->cursor_offset2_x;
v.y = d3d->cursor_y + d3d->cursor_offset2_y;
v.z = 0;
d3d->sprite->SetTransform(&t);
d3d->sprite->Draw(d3d->cursorsurfaced3d, NULL, NULL, &v, 0xffffffff);
MatrixScaling(&t, 1, 1, 0);
d3d->sprite->Flush();
d3d->sprite->SetTransform(&t);
}
if (d3d->mask2texture) {
D3DXMATRIXA16 t;
RECT r;
float srcw = d3d->mask2texture_w;
float srch = d3d->mask2texture_h;
float aspectsrc = srcw / srch;
float aspectdst = (float)d3d->window_w / d3d->window_h;
float w, h;
w = d3d->mask2texture_multx;
h = d3d->mask2texture_multy;
#if 0
if (currprefs.gfx_filteroverlay_pos.width > 0)
w = (float)currprefs.gfx_filteroverlay_pos.width / srcw;
else if (currprefs.gfx_filteroverlay_pos.width == -1)
w = 1.0;
else if (currprefs.gfx_filteroverlay_pos.width <= -24000)
w = w * (-currprefs.gfx_filteroverlay_pos.width - 30000) / 100.0;
if (currprefs.gfx_filteroverlay_pos.height > 0)
h = (float)currprefs.gfx_filteroverlay_pos.height / srch;
else if (currprefs.gfx_filteroverlay_pos.height == -1)
h = 1;
else if (currprefs.gfx_filteroverlay_pos.height <= -24000)
h = h * (-currprefs.gfx_filteroverlay_pos.height - 30000) / 100.0;
#endif
MatrixScaling (&t, w, h, 0);
v.x = 0;
if (d3d->filterd3d->gfx_filteroverlay_pos.x == -1)
v.x = (d3d->window_w - (d3d->mask2texture_w * w)) / 2;
else if (d3d->filterd3d->gfx_filteroverlay_pos.x > -24000)
v.x = d3d->filterd3d->gfx_filteroverlay_pos.x;
else
v.x = (d3d->window_w - (d3d->mask2texture_w * w)) / 2 + (-d3d->filterd3d->gfx_filteroverlay_pos.x - 30100) * d3d->window_w / 100.0;
v.y = 0;
if (d3d->filterd3d->gfx_filteroverlay_pos.y == -1)
v.y = (d3d->window_h - (d3d->mask2texture_h * h)) / 2;
else if (d3d->filterd3d->gfx_filteroverlay_pos.y > -24000)
v.y = d3d->filterd3d->gfx_filteroverlay_pos.y;
else
v.y = (d3d->window_h - (d3d->mask2texture_h * h)) / 2 + (-d3d->filterd3d->gfx_filteroverlay_pos.y - 30100) * d3d->window_h / 100.0;
v.x /= w;
v.y /= h;
v.x = v.y = 0;
v.z = 0;
v.x += d3d->mask2texture_offsetw / w;
r.left = 0;
r.top = 0;
r.right = d3d->mask2texture_w;
r.bottom = d3d->mask2texture_h;
if (showoverlay) {
d3d->sprite->SetTransform(&t);
d3d->sprite->Draw(d3d->mask2texture, &r, NULL, &v, 0xffffffff);
d3d->sprite->Flush();
for (int i = 0; overlayleds[i]; i++) {
bool led = leds[ledtypes[i]] != 0;
if (led || (ledtypes[i] == LED_POWER && currprefs.power_led_dim)) {
LPDIRECT3DTEXTURE9 spr = d3d->mask2textureleds[i];
if (!led && ledtypes[i] == LED_POWER && currprefs.power_led_dim)
spr = d3d->mask2textureled_power_dim;
if (spr) {
v.x = d3d->mask2texture_offsetw / w + d3d->mask2textureledoffsets[i * 2 + 0];
v.y = d3d->mask2textureledoffsets[i * 2 + 1];
v.z = 0;
d3d->sprite->Draw(spr, NULL, NULL, &v, 0xffffffff);
d3d->sprite->Flush();
}
}
}
}
MatrixScaling(&t, 1, 1, 0);
d3d->sprite->SetTransform(&t);
if (d3d->mask2texture_offsetw > 0) {
v.x = 0;
v.y = 0;
r.left = 0;
r.top = 0;
r.right = d3d->mask2texture_offsetw + 1;
r.bottom = d3d->window_h;
d3d->sprite->Draw (d3d->blanktexture, &r, NULL, &v, 0xffffffff);
if (d3d->window_w > d3d->mask2texture_offsetw + d3d->mask2texture_ww) {
v.x = d3d->mask2texture_offsetw + d3d->mask2texture_ww;
v.y = 0;
r.left = 0;
r.top = 0;
r.right = d3d->window_w - (d3d->mask2texture_offsetw + d3d->mask2texture_ww) + 1;
r.bottom = d3d->window_h;
d3d->sprite->Draw(d3d->blanktexture, &r, NULL, &v, 0xffffffff);
}
}
}
if (d3d->ledtexture && (((currprefs.leds_on_screen & STATUSLINE_RTG) && WIN32GFX_IsPicassoScreen(mon)) || ((currprefs.leds_on_screen & STATUSLINE_CHIPSET) && !WIN32GFX_IsPicassoScreen(mon)))) {
int slx, sly;
statusline_getpos(d3d - d3ddata, &slx, &sly, d3d->window_w, d3d->window_h);
v.x = slx;
v.y = sly;
v.z = 0;
d3d->sprite->Draw(d3d->ledtexture, NULL, NULL, &v, 0xffffffff);
}
struct d3d9overlay *ov = d3d->extoverlays;
while (ov) {
if (ov->tex) {
v.x = ov->x;
v.y = ov->y;
v.z = 0;
d3d->sprite->Draw(ov->tex, NULL, NULL, &v, 0xffffffff);
}
ov = ov->next;
}
d3d->sprite->End();
}
#endif
hr = d3d->d3ddev->EndScene();
if (FAILED (hr))
write_log (_T("%s: EndScene() %s\n"), D3DHEAD, D3D_ErrorString (hr));
}
static bool xD3D_setcursor(int monid, int x, int y, int width, int height, bool visible, bool noscale)
{
struct d3dstruct *d3d = &d3ddata[monid];
if (width < 0 || height < 0)
return true;
if (width && height) {
d3d->cursor_offset2_x = d3d->cursor_offset_x * d3d->window_w / width;
d3d->cursor_offset2_y = d3d->cursor_offset_y * d3d->window_h / height;
d3d->cursor_x = x * d3d->window_w / width;
d3d->cursor_y = y * d3d->window_h / height;
} else {
d3d->cursor_x = d3d->cursor_y = 0;
d3d->cursor_offset2_x = d3d->cursor_offset2_y = 0;
}
d3d->cursor_scale = !noscale;
d3d->cursor_v = visible;
return true;
}
static void xD3D_flushtexture(int monid, int miny, int maxy)
{
struct d3dstruct *d3d = &d3ddata[monid];
if (d3d->fakemode || d3d->fulllocked || !d3d->texture || d3d->renderdisabled)
return;
if (miny >= 0 && maxy >= 0) {
RECT r;
maxy++;
r.left = 0;
r.right = d3d->tin_w;
r.top = miny <= 0 ? 0 : miny;
r.bottom = maxy <= d3d->tin_h ? maxy : d3d->tin_h;
if (r.top <= r.bottom) {
HRESULT hr = d3d->texture->AddDirtyRect (&r);
if (FAILED (hr))
write_log (_T("%s: AddDirtyRect(): %s\n"), D3DHEAD, D3D_ErrorString (hr));
//write_log (_T("%d %d\n"), r.top, r.bottom);
}
}
}
static void xD3D_unlocktexture(int monid, int y_start, int y_end)
{
struct d3dstruct *d3d = &d3ddata[monid];
HRESULT hr;
if (!isd3d(d3d) || !d3d->texture)
return;
if (d3d->locked) {
if (currprefs.leds_on_screen & (STATUSLINE_CHIPSET | STATUSLINE_RTG))
updateleds(d3d);
hr = d3d->texture->UnlockRect(0);
if (y_start >= 0)
xD3D_flushtexture(monid, y_start, y_end);
}
d3d->locked = 0;
d3d->fulllocked = 0;
}
static uae_u8 *xD3D_locktexture (int monid, int *pitch, int *height, bool fullupdate)
{
struct d3dstruct *d3d = &d3ddata[monid];
D3DLOCKED_RECT lock;
HRESULT hr;
if (d3d->fakemode) {
*pitch = 0;
return d3d->fakebitmap;
}
if (D3D_needreset (d3d) > 0) {
return NULL;
}
if (!isd3d (d3d) || !d3d->texture)
return NULL;
if (d3d->locked) {
write_log (_T("%s: texture already locked!\n"), D3DHEAD);
return NULL;
}
lock.pBits = NULL;
lock.Pitch = 0;
hr = d3d->texture->LockRect (0, &lock, NULL, fullupdate ? D3DLOCK_DISCARD : D3DLOCK_NO_DIRTY_UPDATE);
if (FAILED (hr)) {
write_log (_T("%s: LockRect failed: %s\n"), D3DHEAD, D3D_ErrorString (hr));
return NULL;
}
d3d->locked = 1;
if (lock.pBits == NULL || lock.Pitch == 0) {
write_log (_T("%s: LockRect returned NULL texture\n"), D3DHEAD);
D3D_unlocktexture(monid, -1, -1);
return NULL;
}
d3d->fulllocked = fullupdate;
*pitch = lock.Pitch;
if (height)
*height = d3d->tin_h;
return (uae_u8*)lock.pBits;
}
static void flushgpu (struct d3dstruct *d3d, bool wait)
{
if (currprefs.turbo_emulation)
return;
if (d3d->query) {
HRESULT hr = d3d->query->Issue (D3DISSUE_END);
if (SUCCEEDED (hr)) {
while (d3d->query->GetData (NULL, 0, D3DGETDATA_FLUSH) == S_FALSE) {
if (!wait)
return;
}
} else {
static int reported;
if (reported < 10) {
reported++;
write_log (_T("%s: query->Issue (D3DISSUE_END) failed: %s\n"), D3DHEAD, D3D_ErrorString (hr));
}
}
}
}
static bool xD3D_renderframe(int monid, int mode, bool immediate)
{
struct d3dstruct *d3d = &d3ddata[monid];
static int vsync2_cnt;
d3d->frames_since_init++;
if (d3d->fakemode)
return true;
if (!isd3d (d3d) || !d3d->texture)
return false;
if (d3d->filenotificationhandle != NULL) {
bool notify = false;
while (WaitForSingleObject (d3d->filenotificationhandle, 0) == WAIT_OBJECT_0) {
if (FindNextChangeNotification (d3d->filenotificationhandle)) {
if (d3d->frames_since_init > 50)
notify = true;
}
}
if (notify) {
d3d->devicelost = 2;
write_log (_T("%s: Shader file modification notification\n"), D3DHEAD);
}
}
if (d3d->vsync2 > 0) {
vsync2_cnt ^= 1;
if (vsync2_cnt == 0)
return true;
}
D3D_render2 (d3d, mode);
flushgpu (d3d, immediate);
return true;
}
static void xD3D_showframe (int monid)
{
struct d3dstruct *d3d = &d3ddata[monid];
if (!isd3d (d3d))
return;
if (currprefs.turbo_emulation) {
if ((!(d3d->dpp.PresentationInterval & D3DPRESENT_INTERVAL_IMMEDIATE) || d3d->variablerefresh) && d3d->wasstilldrawing_broken) {
static int frameskip;
if (currprefs.turbo_emulation && frameskip-- > 0)
return;
frameskip = 10;
}
D3D_showframe2 (d3d, false);
} else {
D3D_showframe2 (d3d, true);
if (d3d->vsync2 == -1 && !currprefs.turbo_emulation) {
D3D_showframe2 (d3d ,true);
}
flushgpu(d3d, true);
}
}
static void xD3D_showframe_special (int monid, int mode)
{
struct d3dstruct *d3d = &d3ddata[monid];
HRESULT hr;
if (!isd3d (d3d))
return;
if (currprefs.turbo_emulation)
return;
if (pause_emulation)
return;
if (mode == 2) {
hr = d3d->d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, d3ddebug ? 0x80 : 0, 0), 0, 0);
}
if (mode == 1) {
D3D_showframe2(d3d, true);
}
flushgpu(d3d, true);
}
static void xD3D_refresh (int monid)
{
struct d3dstruct *d3d = &d3ddata[monid];
if (!isd3d (d3d))
return;
createscanlines(d3d, 0);
for (int i = 0; i < 3; i++) {
D3D_render2(d3d, true);
D3D_showframe2(d3d, true);
}
}
void D3D_getpixelformat (int depth, int *rb, int *gb, int *bb, int *rs, int *gs, int *bs, int *ab, int *as, int *a)
{
switch (depth)
{
case 32:
*rb = 8;
*gb = 8;
*bb = 8;
*ab = 8;
*rs = 16;
*gs = 8;
*bs = 0;
*as = 24;
*a = 0;
break;
case 15:
*rb = 5;
*gb = 5;
*bb = 5;
*ab = 1;
*rs = 10;
*gs = 5;
*bs = 0;
*as = 15;
*a = 0;
break;
case 16:
*rb = 5;
*gb = 6;
*bb = 5;
*ab = 0;
*rs = 11;
*gs = 5;
*bs = 0;
*as = 0;
*a = 0;
break;
}
}
static float xD3D_getrefreshrate(int monid)
{
struct d3dstruct *d3d = &d3ddata[monid];
HRESULT hr;
D3DDISPLAYMODE dmode;
waitfakemode (d3d);
if (!isd3d (d3d))
return -1;
hr = d3d->d3ddev->GetDisplayMode (0, &dmode);
if (FAILED (hr))
return -1;
return dmode.RefreshRate;
}
static void xD3D_guimode(int monid, int guion)
{
struct d3dstruct *d3d = &d3ddata[monid];
HRESULT hr;
if (guion != 0 && guion != 1)
return;
waitfakemode (d3d);
if (!isd3d (d3d))
return;
D3D_render2(d3d, true);
D3D_showframe2(d3d, true);
hr = d3d->d3ddev->SetDialogBoxMode (guion ? TRUE : FALSE);
if (FAILED (hr))
write_log (_T("%s: SetDialogBoxMode %s\n"), D3DHEAD, D3D_ErrorString (hr));
d3d->guimode = guion;
}
LPDIRECT3DSURFACE9 D3D_capture(int monid, int *w, int *h, int *bits, bool rendertarget)
{
struct d3dstruct *d3d = &d3ddata[monid];
HRESULT hr;
LPDIRECT3DSURFACE9 ret = NULL;
waitfakemode(d3d);
if (!isd3d(d3d))
return NULL;
if (rendertarget) {
LPDIRECT3DSURFACE9 rt;
hr = d3d->d3ddev->GetRenderTarget(0, &rt);
if (FAILED(hr)) {
write_log(_T("%s: D3D_capture() GetRenderTarget() failed: %s\n"), D3DHEAD, D3D_ErrorString(hr));
return NULL;
}
hr = d3d->d3ddev->GetRenderTargetData(rt, d3d->screenshotsurface);
rt->Release();
if (FAILED(hr)) {
write_log(_T("%s: D3D_capture() GetRenderTargetData() failed: %s\n"), D3DHEAD, D3D_ErrorString(hr));
return NULL;
}
ret = d3d->screenshotsurface;
} else {
hr = d3d->texture->GetSurfaceLevel(0, &ret);
if (FAILED(hr)) {
write_log(_T("%s: D3D_capture() GetSurfaceLevel() failed: %s\n"), D3DHEAD, D3D_ErrorString(hr));
return NULL;
}
}
*w = d3d->window_w;
*h = d3d->window_h;
*bits = d3d->t_depth;
return ret;
}
static HDC xD3D_getDC(int monid, HDC hdc)
{
struct d3dstruct *d3d = &d3ddata[monid];
static LPDIRECT3DSURFACE9 bb;
HRESULT hr;
waitfakemode (d3d);
if (!isd3d (d3d))
return 0;
if (!hdc) {
hr = d3d->d3ddev->GetBackBuffer (0, 0, D3DBACKBUFFER_TYPE_MONO, &bb);
if (FAILED (hr)) {
write_log (_T("%s: GetBackBuffer() failed: %s\n"), D3DHEAD, D3D_ErrorString (hr));
return 0;
}
hr = bb->GetDC (&hdc);
if (SUCCEEDED (hr))
return hdc;
write_log (_T("%s: GetDC() failed: %s\n"), D3DHEAD, D3D_ErrorString (hr));
}
if (bb) {
if (hdc)
bb->ReleaseDC (hdc);
bb->Release ();
bb = NULL;
}
return 0;
}
static int xD3D_isenabled(int monid)
{
struct d3dstruct *d3d = &d3ddata[monid];
return d3d->d3d_enabled ? 1 : 0;
}
static uae_u8 *xD3D_setcursorsurface(int monid, int *pitch)
{
struct d3dstruct *d3d = &d3ddata[monid];
if (pitch) {
D3DLOCKED_RECT locked;
if (!d3d->cursorsurfaced3d)
return NULL;
HRESULT hr = d3d->cursorsurfaced3d->LockRect(0, &locked, NULL, 0);
if (FAILED(hr))
return NULL;
*pitch = locked.Pitch;
return (uae_u8*)locked.pBits;
} else {
d3d->cursorsurfaced3d->UnlockRect(0);
return NULL;
}
}
static bool xD3D_getscanline(int *scanline, bool *invblank)
{
struct d3dstruct *d3d = &d3ddata[0];
HRESULT hr;
D3DRASTER_STATUS rt;
if (!isd3d(d3d))
return false;
if (d3d->d3dswapchain)
hr = d3d->d3dswapchain->GetRasterStatus(&rt);
else
hr = d3d->d3ddev->GetRasterStatus(0, &rt);
if (FAILED(hr))
return false;
*scanline = rt.ScanLine;
*invblank = rt.InVBlank != FALSE;
return true;
}
static bool xD3D_run(int monid)
{
struct d3dstruct *d3d = &d3ddata[monid];
return false;
}
static bool xD3D_extoverlay(struct extoverlay *ext)
{
struct d3dstruct *d3d = &d3ddata[0];
struct d3d9overlay *ov, *ovprev, *ov2;
LPDIRECT3DTEXTURE9 s;
D3DLOCKED_RECT locked;
HRESULT hr;
s = NULL;
ov = d3d->extoverlays;
ovprev = NULL;
while (ov) {
if (ov->id == ext->idx) {
s = ov->tex;
break;
}
ovprev = ov;
ov = ov->next;
}
write_log(_T("extoverlay %d: x=%d y=%d %d*%d data=%p ovl=%p\n"), ext->idx, ext->xpos, ext->ypos, ext->width, ext->height, ext->data, ov);
if (!s && (ext->width <= 0 || ext->height <= 0))
return false;
if (!ext->data && s && (ext->width == 0 || ext->height == 0)) {
ov->x = ext->xpos;
ov->y = ext->ypos;
return true;
}
if (ov && s) {
if (ovprev) {
ovprev->next = ov->next;
} else {
d3d->extoverlays = ov->next;
}
s->Release();
xfree(ov);
if (ext->width <= 0 || ext->height <= 0)
return true;
}
if (ext->width <= 0 || ext->height <= 0)
return false;
ov = xcalloc(d3d9overlay, 1);
s = createtext(d3d, ext->width, ext->height, D3DFMT_A8R8G8B8);
if (!s) {
xfree(ov);
return false;
}
ov->tex = s;
ov->id = ext->idx;
ov2 = d3d->extoverlays;
ovprev = NULL;
for (;;) {
if (ov2 == NULL || ov2->id >= ov->id) {
if (ov2 == d3d->extoverlays) {
d3d->extoverlays = ov;
ov->next = ov2;
} else {
ov->next = ovprev->next;
ovprev->next = ov;
}
break;
}
ovprev = ov2;
ov2 = ov2->next;
}
ov->x = ext->xpos;
ov->y = ext->ypos;
hr = s->LockRect(0, &locked, NULL, 0);
if (SUCCEEDED(hr)) {
for (int y = 0; y < ext->height; y++) {
memcpy((uae_u8*)locked.pBits + y * locked.Pitch, ext->data + y * ext->width * 4, ext->width * 4);
}
s->UnlockRect(0);
}
return true;
}
void d3d9_select(void)
{
D3D_free = xD3D_free;
D3D_init = xD3D_init;
D3D_alloctexture = xD3D_alloctexture;
D3D_refresh = xD3D_refresh;
D3D_renderframe = xD3D_renderframe;
D3D_showframe = xD3D_showframe;
D3D_showframe_special = xD3D_showframe_special;
D3D_locktexture = xD3D_locktexture;
D3D_unlocktexture = xD3D_unlocktexture;
D3D_flushtexture = xD3D_flushtexture;
D3D_guimode = xD3D_guimode;
D3D_getDC = xD3D_getDC;
D3D_isenabled = xD3D_isenabled;
D3D_clear = xD3D_clear;
D3D_canshaders = xD3D_canshaders;
D3D_goodenough = xD3D_goodenough;
D3D_setcursor = xD3D_setcursor;
D3D_setcursorsurface = xD3D_setcursorsurface;
D3D_getrefreshrate = xD3D_getrefreshrate;
D3D_restore = xD3D_restore;
D3D_resize = NULL;
D3D_change = NULL;
D3D_getscalerect = xD3D_getscalerect;
D3D_run = xD3D_run;
D3D_debug = xD3D_debug;
D3D_led = xD3D_led;
D3D_getscanline = xD3D_getscanline;
D3D_extoverlay = xD3D_extoverlay;
}
#endif