WinUAE/od-win32/direct3d11.cpp
2024-02-02 20:52:30 +02:00

5635 lines
163 KiB
C++

/* Direct3D 11 graphics renderer */
#include <windows.h>
#include "resource.h"
#include <DXGI1_5.h>
#include <dxgi1_6.h>
#include <d3d11.h>
#include <D3Dcompiler.h>
#include <wrl/client.h>
using Microsoft::WRL::ComPtr;
#include "sysconfig.h"
#include "sysdeps.h"
#include "options.h"
#include "xwin.h"
#include "render.h"
#include "win32.h"
#include "win32gfx.h"
#include "direct3d.h"
#include "uae.h"
#include "custom.h"
#include "gfxfilter.h"
#include "zfile.h"
#include "statusline.h"
#include "hq2x_d3d.h"
#include "gui.h"
#include "gfxboard.h"
#include "d3dx.h"
#include "shaders/PixelShaderPlain.h"
#include "shaders/PixelShaderPlain_HDR.h"
#include "shaders/PixelShaderAlpha.h"
#include "shaders/PixelShaderAlpha_HDR.h"
#include "shaders/PixelShaderMask.h"
#include "shaders/PixelShaderMask_HDR.h"
#include "shaders/VertexShader.h"
#include "FX11/d3dx11effect.h"
#include <process.h>
#include <Dwmapi.h>
void (*D3D_free)(int, bool immediate);
const TCHAR *(*D3D_init)(HWND ahwnd, int, int w_w, int h_h, int depth, int *freq, int mmulth, int mmultv, int *err);
bool (*D3D_alloctexture)(int, int, int);
void(*D3D_refresh)(int);
bool(*D3D_renderframe)(int, int,bool);
void(*D3D_showframe)(int);
void(*D3D_showframe_special)(int, int);
uae_u8 *(*D3D_locktexture)(int, int*, int*, int*, int);
void (*D3D_unlocktexture)(int, int, int);
void (*D3D_flushtexture)(int, int miny, int maxy);
void (*D3D_guimode)(int, int);
HDC (*D3D_getDC)(int, HDC hdc);
int (*D3D_isenabled)(int);
void (*D3D_clear)(int);
int (*D3D_canshaders)(void);
int (*D3D_goodenough)(void);
bool (*D3D_setcursor)(int, int x, int y, int width, int height, float mx, float my, bool visible, bool noscale);
uae_u8 *(*D3D_setcursorsurface)(int, bool, int *pitch);
float (*D3D_getrefreshrate)(int);
void(*D3D_restore)(int, bool);
void(*D3D_resize)(int, int);
void (*D3D_change)(int, int);
bool(*D3D_getscalerect)(int, float *mx, float *my, float *sx, float *sy, int width, int height);
bool(*D3D_run)(int);
int(*D3D_debug)(int, int);
void(*D3D_led)(int, int, int);
bool(*D3D_getscanline)(int*, bool*);
bool(*D3D_extoverlay)(struct extoverlay*,int);
void(*D3D_paint)(void);
static HMODULE hd3d11, hdxgi, hd3dcompiler, dwmapi;
static int d3d11_feature_level;
static int leds[LED_MAX];
static int debugcolors;
static bool cannoclear;
static bool noclear;
static int clearcnt;
static int slicecnt;
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 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 shadertex
{
ID3D11Texture2D *tex;
ID3D11ShaderResourceView *rv;
ID3D11RenderTargetView *rt;
D3D11_VIEWPORT *vp;
};
#define MAX_TECHNIQUE_LAYOUTS 8
struct shaderdata11
{
int type;
bool psPreProcess;
int worktex_width;
int worktex_height;
int targettex_width;
int targettex_height;
ID3D11ShaderResourceView *masktexturerv;
ID3D11Texture2D *masktexture;
struct shadertex lpWorkTexture1;
struct shadertex lpWorkTexture2;
struct shadertex lpTempTexture;
ID3D11Texture3D *lpHq2xLookupTexture;
ID3D11ShaderResourceView *lpHq2xLookupTexturerv;
int masktexture_w, masktexture_h;
ID3DX11Effect *effect;
ID3DX11EffectScalarVariable *framecounterHandle;
ID3D11InputLayout *layouts[MAX_TECHNIQUE_LAYOUTS];
ID3D11Buffer *indexBuffer;
ID3D11Buffer *vertexBuffer;
D3D11_VIEWPORT viewport;
// Technique stuff
ID3DX11EffectTechnique *m_PreprocessTechnique1EffectHandle;
int PreprocessTechnique1EffectIndex;
ID3DX11EffectTechnique *m_PreprocessTechnique2EffectHandle;
int PreprocessTechnique2EffectIndex;
ID3DX11EffectTechnique *m_CombineTechniqueEffectHandle;
int CombineTechniqueEffectIndex;
// Matrix Handles
ID3DX11EffectMatrixVariable *m_MatWorldEffectHandle;
ID3DX11EffectMatrixVariable *m_MatViewEffectHandle;
ID3DX11EffectMatrixVariable *m_MatProjEffectHandle;
ID3DX11EffectMatrixVariable *m_MatWorldViewEffectHandle;
ID3DX11EffectMatrixVariable *m_MatViewProjEffectHandle;
ID3DX11EffectMatrixVariable *m_MatWorldViewProjEffectHandle;
// Vector Handles
ID3DX11EffectVectorVariable *m_SourceDimsEffectHandle;
ID3DX11EffectVectorVariable *m_InputDimsEffectHandle;
ID3DX11EffectVectorVariable *m_TargetDimsEffectHandle;
ID3DX11EffectVectorVariable *m_TexelSizeEffectHandle;
ID3DX11EffectVectorVariable *m_ScaleEffectHandle;
// Texture Handles
ID3DX11EffectShaderResourceVariable *m_SourceTextureEffectHandle;
ID3DX11EffectShaderResourceVariable *m_WorkingTexture1EffectHandle;
ID3DX11EffectShaderResourceVariable *m_WorkingTexture2EffectHandle;
ID3DX11EffectShaderResourceVariable *m_Hq2xLookupTextureHandle;
ID3DX11EffectStringVariable *m_strName;
ID3DX11EffectScalarVariable *m_scale;
TCHAR loadedshader[256];
};
#define MAX_SHADERS (2 * MAX_FILTERSHADERS + 2)
#define SHADER_POST 0
#define VERTEXCOUNT 4
#define INDEXCOUNT 6
struct d3d11sprite
{
ID3D11Texture2D *texture;
ID3D11ShaderResourceView *texturerv;
ID3D11VertexShader *vertexshader;
ID3D11PixelShader *pixelshader;
ID3D11InputLayout *layout;
ID3D11Buffer *vertexbuffer, *indexbuffer;
ID3D11Buffer *matrixbuffer;
int width, height;
float x, y;
float outwidth, outheight;
bool enabled;
bool alpha;
bool bilinear;
bool rotation;
bool screenlimit;
uae_u8 *texbuf;
bool updated;
bool empty;
};
struct d3doverlay
{
struct d3doverlay *next;
int id;
struct d3d11sprite s;
};
struct d3d11struct
{
int num;
IDXGISwapChain1 *m_swapChain;
ID3D11Device *m_device;
ID3D11DeviceContext *m_deviceContext;
ID3D11RenderTargetView *m_renderTargetView;
ID3D11RasterizerState *m_rasterState;
D3DXMATRIX m_orthoMatrix;
D3DXMATRIX m_worldMatrix;
D3DXMATRIX m_viewMatrix;
D3DXMATRIX m_matPreProj;
D3DXMATRIX m_matPreView;
D3DXMATRIX m_matPreWorld;
D3DXMATRIX m_matProj;
D3DXMATRIX m_matView;
D3DXMATRIX m_matWorld;
D3DXMATRIX m_matProj2;
D3DXMATRIX m_matView2;
D3DXMATRIX m_matWorld2;
D3DXMATRIX m_matProj_out;
D3DXMATRIX m_matView_out;
D3DXMATRIX m_matWorld_out;
D3D11_VIEWPORT viewport;
ID3D11Buffer *m_vertexBuffer, *m_indexBuffer;
ID3D11Buffer *m_matrixBuffer;
ID3D11Buffer *m_psBuffer;
int m_screenWidth, m_screenHeight;
int m_bitmapWidth, m_bitmapHeight;
int m_bitmapWidth2, m_bitmapHeight2;
int m_bitmapWidthX, m_bitmapHeightX;
int index_buffer_bytes;
float m_positionX, m_positionY, m_positionZ;
float m_rotationX, m_rotationY, m_rotationZ;
ID3D11ShaderResourceView *texture2drv;
ID3D11ShaderResourceView *sltexturerv;
ID3D11Texture2D *texture2d, *texture2dstaging;
ID3D11Texture2D *sltexture;
ID3D11Texture2D *screenshottexturert, *screenshottexturetx;
ID3D11VertexShader *m_vertexShader;
ID3D11PixelShader *m_pixelShader, *m_pixelShaderSL, *m_pixelShaderMask;
ID3D11SamplerState *m_sampleState_point_clamp, *m_sampleState_linear_clamp;
ID3D11SamplerState *m_sampleState_point_wrap, *m_sampleState_linear_wrap;
ID3D11InputLayout *m_layout;
ID3D11BlendState *m_alphaEnableBlendingState;
ID3D11BlendState *m_alphaDisableBlendingState;
struct shadertex lpPostTempTexture;
int texturelocked;
DXGI_FORMAT scrformat;
DXGI_FORMAT texformat;
bool m_tearingSupport;
int dmult, dmultxh, dmultxv, dmode;
float xoffset, yoffset;
float xmult, ymult;
DXGI_SWAP_CHAIN_DESC1 swapChainDesc;
DXGI_SWAP_CHAIN_FULLSCREEN_DESC fsSwapChainDesc;
IDXGIOutput *outputAdapter;
HWND ahwnd;
int fsmode;
bool fsresizedo;
bool fsmodechange;
bool invalidmode;
int vblankintervals;
bool blackscreen;
int framecount;
UINT syncinterval;
float vblank;
DWM_FRAME_COUNT lastframe;
int frames_since_init;
bool resizeretry;
bool d3dinit_done;
bool hdr;
struct d3d11sprite osd;
struct d3d11sprite hwsprite;
struct d3d11sprite mask2texture;
struct d3d11sprite mask2textureleds[9], mask2textureled_power_dim;
int mask2textureledoffsets[9 * 2];
struct d3d11sprite blanksprite;
struct d3doverlay *extoverlays;
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;
RECT mask2rect;
IDXGISurface1 *hdc_surface;
HANDLE filenotificationhandle;
RECT sr2, dr2, zr2;
int guimode;
int delayedfs;
int device_errors;
bool delayedrestore;
bool reloadshaders;
int ledwidth, ledheight;
int statusbar_hx, statusbar_vx;
int cursor_offset_x, cursor_offset_y, cursor_offset2_x, cursor_offset2_y;
float cursor_x, cursor_y;
bool cursor_v, cursor_scale;
struct gfx_filterdata *filterd3d;
int filterd3didx;
int scanline_osl1, scanline_osl2, scanline_osl3, scanline_osl4;
struct shaderdata11 shaders[MAX_SHADERS];
ID3DX11EffectTechnique *technique;
ID3DX11EffectPass *effectpass;
#ifndef NDEBUG
ID3D11InfoQueue *m_debugInfoQueue;
ID3D11Debug *m_debug;
#endif
};
#define NUMVERTICES 8
struct TLVERTEX {
D3DXVECTOR3 position; // vertex position
D3DCOLOR diffuse;
D3DXVECTOR2 texcoord; // texture coords
};
struct VertexType
{
D3DXVECTOR3 position;
D3DXVECTOR2 texture;
D3DXVECTOR2 sltexture;
};
struct MatrixBufferType
{
D3DXMATRIX world;
D3DXMATRIX view;
D3DXMATRIX projection;
};
struct PSBufferType
{
float brightness;
float contrast;
float d2;
float d3;
};
static struct d3d11struct d3d11data[MAX_AMIGAMONITORS];
typedef HRESULT (WINAPI* CREATEDXGIFACTORY1)(REFIID riid, void **ppFactory);
typedef HRESULT (WINAPI* D3DCOMPILEFROMFILE)(LPCWSTR pFileName,
CONST D3D_SHADER_MACRO* pDefines,
ID3DInclude* pInclude,
LPCSTR pEntrypoint,
LPCSTR pTarget,
UINT Flags1,
UINT Flags2,
ID3DBlob** ppCode,
ID3DBlob** ppErrorMsgs);
typedef HRESULT(WINAPI* D3DCOMPILE)(LPCVOID pSrcData,
SIZE_T SrcDataSize,
LPCSTR pSourceName,
CONST D3D_SHADER_MACRO* pDefines,
ID3DInclude* pInclude,
LPCSTR pEntrypoint,
LPCSTR pTarget,
UINT Flags1,
UINT Flags2,
ID3DBlob** ppCode,
ID3DBlob** ppErrorMsgs);
typedef HRESULT (WINAPI* D3DCOMPILE2)(LPCVOID pSrcData,
SIZE_T SrcDataSize,
LPCSTR pSourceName,
CONST D3D_SHADER_MACRO* pDefines,
ID3DInclude* pInclude,
LPCSTR pEntrypoint,
LPCSTR pTarget,
UINT Flags1,
UINT Flags2,
UINT SecondaryDataFlags,
LPCVOID pSecondaryData,
SIZE_T SecondaryDataSize,
ID3DBlob** ppCode,
ID3DBlob** ppErrorMsgs);
typedef HRESULT(WINAPI *D3DREFLECT)(LPCVOID pSrcData, SIZE_T SrcDataSize, REFIID pInterface, void **ppReflector);
typedef HRESULT(WINAPI *D3DGETBLOBPART)(LPCVOID pSrcData, SIZE_T SrcDataSize, D3D_BLOB_PART Part, UINT Flags, ID3DBlob** ppPart);
typedef HRESULT(WINAPI *DWMGETCOMPOSITIONTIMINGINFO)(HWND hwnd, DWM_TIMING_INFO *pTimingInfo);
static PFN_D3D11_CREATE_DEVICE pD3D11CreateDevice;
static CREATEDXGIFACTORY1 pCreateDXGIFactory1;
static DWMGETCOMPOSITIONTIMINGINFO pDwmGetCompositionTimingInfo;
D3DCOMPILE ppD3DCompile;
D3DCOMPILE2 ppD3DCompile2;
D3DCOMPILEFROMFILE pD3DCompileFromFile;
D3DREFLECT pD3DReflect;
D3DGETBLOBPART pD3DGetBlobPart;
static int isfs(struct d3d11struct *d3d)
{
int fs = isfullscreen();
if (fs > 0 && d3d->guimode)
return -1;
return fs;
}
static void TurnOnAlphaBlending(struct d3d11struct *d3d)
{
float blendFactor[4];
// Setup the blend factor.
blendFactor[0] = 0.0f;
blendFactor[1] = 0.0f;
blendFactor[2] = 0.0f;
blendFactor[3] = 0.0f;
// Turn on the alpha blending.
d3d->m_deviceContext->OMSetBlendState(d3d->m_alphaEnableBlendingState, blendFactor, 0xffffffff);
}
static void TurnOffAlphaBlending(struct d3d11struct *d3d)
{
float blendFactor[4];
// Setup the blend factor.
blendFactor[0] = 0.0f;
blendFactor[1] = 0.0f;
blendFactor[2] = 0.0f;
blendFactor[3] = 0.0f;
// Turn off the alpha blending.
d3d->m_deviceContext->OMSetBlendState(d3d->m_alphaDisableBlendingState, blendFactor, 0xffffffff);
}
static float get_rotation(struct d3d11struct *d3d, int monid)
{
struct amigadisplay *ad = &adisplays[monid];
int rota = currprefs.gf[ad->picasso_on ? GF_RTG : ad->interlace_on ? GF_INTERLACE : GF_NORMAL].gfx_filter_rotation;
const float PI = 3.14159265358979f;
float rot = PI / 180.0f * rota;
return rot;
}
#define D3DX_DEFAULT ((UINT) -1)
static bool psEffect_ParseParameters(struct d3d11struct *d3d, ID3DX11Effect *effect, struct shaderdata11 *s, char *fxname, char *data, UINT flags1)
{
HRESULT hr = S_OK;
// Look at parameters for semantics and annotations that we know how to interpret
if (effect == NULL || !effect->IsValid())
return false;
D3DX11_EFFECT_DESC effectDesc;
hr = effect->GetDesc(&effectDesc);
if (FAILED(hr))
return false;
if (!effectDesc.Techniques) {
write_log(_T("D3D11 No techniques found!\n"));
return false;
}
ID3DX11EffectVariable *v = effect->GetVariableByName("framecounter");
if (v && v->IsValid()) {
s->framecounterHandle = v->AsScalar();
}
for (UINT iParam = 0; iParam < effectDesc.GlobalVariables; iParam++) {
ID3DX11EffectVariable *hParam;
D3DX11_EFFECT_VARIABLE_DESC ParamDesc;
hParam = effect->GetVariableByIndex(iParam);
if (!hParam->IsValid())
continue;
hr = hParam->GetDesc(&ParamDesc);
TCHAR *name = au(ParamDesc.Name);
TCHAR *semantic = au(ParamDesc.Semantic);
write_log(_T("FX Flags=%08x Ans=%d Name='%s' Semantic='%s'\n"), ParamDesc.Flags, ParamDesc.Annotations, name, semantic);
xfree(semantic);
xfree(name);
if (ParamDesc.Semantic) {
if (strcmpi(ParamDesc.Semantic, "world") == 0)
s->m_MatWorldEffectHandle = hParam->AsMatrix();
else if (strcmpi(ParamDesc.Semantic, "view") == 0)
s->m_MatViewEffectHandle = hParam->AsMatrix();
else if (strcmpi(ParamDesc.Semantic, "projection") == 0)
s->m_MatProjEffectHandle = hParam->AsMatrix();
else if (strcmpi(ParamDesc.Semantic, "worldview") == 0)
s->m_MatWorldViewEffectHandle = hParam->AsMatrix();
else if (strcmpi(ParamDesc.Semantic, "viewprojection") == 0)
s->m_MatViewProjEffectHandle = hParam->AsMatrix();
else if (strcmpi(ParamDesc.Semantic, "worldviewprojection") == 0)
s->m_MatWorldViewProjEffectHandle = hParam->AsMatrix();
if (strcmpi(ParamDesc.Semantic, "sourcedims") == 0)
s->m_SourceDimsEffectHandle = hParam->AsVector();
if (strcmpi(ParamDesc.Semantic, "inputdims") == 0)
s->m_InputDimsEffectHandle = hParam->AsVector();
if (strcmpi(ParamDesc.Semantic, "targetdims") == 0)
s->m_TargetDimsEffectHandle = hParam->AsVector();
else if (strcmpi(ParamDesc.Semantic, "texelsize") == 0)
s->m_TexelSizeEffectHandle = hParam->AsVector();
else if (strcmpi(ParamDesc.Semantic, "sourcescale") == 0)
s->m_ScaleEffectHandle = hParam->AsVector();
if (strcmpi(ParamDesc.Semantic, "SCALING") == 0)
s->m_scale = hParam->AsScalar();
if (strcmpi(ParamDesc.Semantic, "SOURCETEXTURE") == 0)
s->m_SourceTextureEffectHandle = hParam->AsShaderResource();
if (strcmpi(ParamDesc.Semantic, "WORKINGTEXTURE") == 0)
s->m_WorkingTexture1EffectHandle = hParam->AsShaderResource();
if (strcmpi(ParamDesc.Semantic, "WORKINGTEXTURE1") == 0)
s->m_WorkingTexture2EffectHandle = hParam->AsShaderResource();
if (strcmpi(ParamDesc.Semantic, "HQ2XLOOKUPTEXTURE") == 0)
s->m_Hq2xLookupTextureHandle = hParam->AsShaderResource();
ID3DX11EffectStringVariable *pstrTechnique = NULL;
LPCSTR name;
if (strcmpi(ParamDesc.Semantic, "COMBINETECHNIQUE") == 0) {
pstrTechnique = hParam->AsString();
pstrTechnique->GetString(&name);
s->m_CombineTechniqueEffectHandle = effect->GetTechniqueByName(name);
} else if (strcmpi(ParamDesc.Semantic, "PREPROCESSTECHNIQUE") == 0) {
pstrTechnique = hParam->AsString();
pstrTechnique->GetString(&name);
s->m_PreprocessTechnique1EffectHandle = effect->GetTechniqueByName(name);
} else if (strcmpi(ParamDesc.Semantic, "PREPROCESSTECHNIQUE1") == 0) {
pstrTechnique = hParam->AsString();
pstrTechnique->GetString(&name);
s->m_PreprocessTechnique2EffectHandle = effect->GetTechniqueByName(name);
} else if (strcmpi(ParamDesc.Semantic, "NAME") == 0) {
s->m_strName = hParam->AsString();
}
if (pstrTechnique)
pstrTechnique->Release();
}
LPCSTR pstrFunctionHandle = NULL;
LPCSTR pstrTarget = NULL;
LPCSTR pstrTextureType = NULL;
INT Width = D3DX_DEFAULT;
INT Height = D3DX_DEFAULT;
INT Depth = D3DX_DEFAULT;
for (UINT iAnnot = 0; iAnnot < ParamDesc.Annotations; iAnnot++) {
ID3DX11EffectVariable *hAnnot = hParam->GetAnnotationByIndex(iAnnot);
D3DX11_EFFECT_VARIABLE_DESC AnnotDesc;
ID3DX11EffectStringVariable *pstrName = NULL;
hr = hAnnot->GetDesc(&AnnotDesc);
if (FAILED(hr)) {
write_log(_T("Direct3D11: GetParameterDescAnnot(%d) failed: %s\n"), iAnnot, hr);
continue;
}
TCHAR *name = au(AnnotDesc.Name);
TCHAR *semantic = au(AnnotDesc.Semantic);
write_log(_T("Effect Annotation Name='%s' Semantic='%s'\n"), name, semantic);
xfree(semantic);
xfree(name);
if (strcmpi(AnnotDesc.Name, "name") == 0) {
pstrName = hAnnot->AsString();
} else if (strcmpi(AnnotDesc.Name, "function") == 0) {
hAnnot->AsString()->GetString(&pstrFunctionHandle);
} else if (strcmpi(AnnotDesc.Name, "target") == 0) {
hAnnot->AsString()->GetString(&pstrTarget);
} else if (strcmpi(AnnotDesc.Name, "width") == 0) {
hAnnot->AsScalar()->GetInt(&Width);
} else if (strcmpi(AnnotDesc.Name, "height") == 0) {
hAnnot->AsScalar()->GetInt(&Height);
} else if (strcmpi(AnnotDesc.Name, "depth") == 0) {
hAnnot->AsScalar()->GetInt(&Depth);
} else if (strcmpi(AnnotDesc.Name, "type") == 0) {
hAnnot->AsString()->GetString(&pstrTextureType);
}
if (pstrName)
pstrName->Release();
hAnnot->Release();
}
if (pstrFunctionHandle != NULL) {
#if 0
if (pstrTarget == NULL || strcmp(pstrTarget, "tx_1_1"))
pstrTarget = "tx_1_0";
ID3DBlob *errors = NULL;
ID3DBlob *code = NULL;
TCHAR *n = au(pstrFunctionHandle);
hr = ppD3DCompile2(data, strlen(data), fxname, NULL, D3D_COMPILE_STANDARD_FILE_INCLUDE, pstrFunctionHandle, pstrTarget, flags1, 0, 0, NULL, 0, &code, &errors);
if (SUCCEEDED(hr)) {
if (Width == D3DX_DEFAULT)
Width = 64;
if (Height == D3DX_DEFAULT)
Height = 64;
if (Depth == D3DX_DEFAULT)
Depth = 64;
ID3D11Resource *res = NULL;
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
memset(&srvDesc, 0, sizeof srvDesc);
if (pstrTextureType && strcmpi(pstrTextureType, "volume") == 0) {
} else if (pstrTextureType && strcmpi(pstrTextureType, "cube") == 0) {
} else {
ID3D11Texture2D *texture;
D3D11_TEXTURE2D_DESC desc;
memset(&desc, 0, sizeof desc);
desc.Width = Width;
desc.Height = Height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = d3d->scrformat;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
hr = d3d->m_device->CreateTexture2D(&desc, NULL, &texture);
if (SUCCEEDED(hr)) {
res = texture;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
} else {
write_log(_T("CreateTexture2D ('%s' %d%*%d) failed: %08x\n"), n, Width, Height, hr);
}
}
if (res) {
ID3D11ShaderResourceView *rv = NULL;
srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Texture2D.MipLevels = 1;
srvDesc.Format = d3d->scrformat;
hr = d3d->m_device->CreateShaderResourceView(res, &srvDesc, &rv);
if (SUCCEEDED(hr)) {
hParam->AsShaderResource()->SetResource(rv);
rv->Release();
} else {
write_log(_T("CreateShaderResourceView ('%s' %dx%d) failed: %08x\n"), n, Width, Height, hr);
}
res->Release();
}
} else {
void *p = errors->GetBufferPointer();
TCHAR *s = au((char*)p);
write_log(_T("Effect compiler '%s' errors:\n%s\n"), n, s);
xfree(s);
}
xfree(n);
if (errors)
errors->Release();
#endif
}
hParam->Release();
}
if (!s->m_CombineTechniqueEffectHandle && effectDesc.Techniques > 0) {
s->m_CombineTechniqueEffectHandle = effect->GetTechniqueByIndex(0);
}
return true;
}
static bool allocfxdata(struct d3d11struct *d3d, struct shaderdata11 *s)
{
struct TLVERTEX *vertices[NUMVERTICES] = { 0 };
D3D11_BUFFER_DESC vertexBufferDesc;
D3D11_SUBRESOURCE_DATA vertexData;
D3D11_BUFFER_DESC indexBufferDesc;
D3D11_SUBRESOURCE_DATA indexData;
uae_u32 indices[INDEXCOUNT * 2];
vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
vertexBufferDesc.ByteWidth = sizeof(struct TLVERTEX) * NUMVERTICES;
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
vertexBufferDesc.MiscFlags = 0;
vertexBufferDesc.StructureByteStride = 0;
// Give the subresource structure a pointer to the vertex data.
vertexData.pSysMem = vertices;
vertexData.SysMemPitch = 0;
vertexData.SysMemSlicePitch = 0;
// Now create the vertex buffer.
HRESULT hr = d3d->m_device->CreateBuffer(&vertexBufferDesc, &vertexData, &s->vertexBuffer);
if (FAILED(hr))
{
write_log(_T("ID3D11Device CreateBuffer(fxvertex) %08x\n"), hr);
return false;
}
#ifndef NDEBUG
static const char vname[] = "fxvertexbuffer";
s->vertexBuffer->SetPrivateData(WKPDID_D3DDebugObjectName, sizeof(vname) - 1, vname);
#endif
static const uae_u16 indexes[INDEXCOUNT * 2] = {
2, 1, 0, 2, 3, 1,
6, 5, 4, 6, 7, 5
};
// Load the index array with data.
for (int i = 0; i < INDEXCOUNT * 2; i++)
{
if (d3d->index_buffer_bytes == 4)
((uae_u32*)indices)[i] = indexes[i];
else
((uae_u16*)indices)[i] = indexes[i];
}
// Set up the description of the static index buffer.
indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
indexBufferDesc.ByteWidth = d3d->index_buffer_bytes * INDEXCOUNT * 2;
indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
indexBufferDesc.CPUAccessFlags = 0;
indexBufferDesc.MiscFlags = 0;
indexBufferDesc.StructureByteStride = 0;
// Give the subresource structure a pointer to the index data.
indexData.pSysMem = indices;
indexData.SysMemPitch = 0;
indexData.SysMemSlicePitch = 0;
// Create the index buffer.
hr = d3d->m_device->CreateBuffer(&indexBufferDesc, &indexData, &s->indexBuffer);
if (FAILED(hr))
{
write_log(_T("ID3D11Device CreateBuffer(index) %08x\n"), hr);
return false;
}
#ifndef NDEBUG
static const char iname[] = "fxindexbuffer";
s->indexBuffer->SetPrivateData(WKPDID_D3DDebugObjectName, sizeof(iname) - 1, iname);
#endif
return true;
}
static bool createfxvertices(struct d3d11struct *d3d, struct shaderdata11 *s)
{
HRESULT hr;
struct TLVERTEX *vertices;
D3D11_MAPPED_SUBRESOURCE mappedResource;
float sizex, sizey;
sizex = 1.0f;
sizey = 1.0f;
hr = d3d->m_deviceContext->Map(s->vertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
if (FAILED(hr))
{
write_log(_T("ID3D11DeviceContext map(fxvertex) %08x\n"), hr);
return false;
}
vertices = (struct TLVERTEX*)mappedResource.pData;
//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;
d3d->m_deviceContext->Unmap(s->vertexBuffer, 0);
return true;
}
static int createfxlayout(struct d3d11struct *d3d, struct shaderdata11 *s, ID3DX11EffectTechnique *technique, int idx)
{
HRESULT hr;
if (!technique || !technique->IsValid())
return -1;
D3DX11_TECHNIQUE_DESC techDesc;
hr = technique->GetDesc(&techDesc);
for (int pass = 0; pass < techDesc.Passes && idx < MAX_TECHNIQUE_LAYOUTS; pass++) {
ID3DX11EffectPass *effectpass = technique->GetPassByIndex(pass);
D3DX11_PASS_SHADER_DESC effectVsDesc;
D3DX11_EFFECT_SHADER_DESC effectVsDesc2;
hr = effectpass->GetVertexShaderDesc(&effectVsDesc);
hr = effectVsDesc.pShaderVariable->GetShaderDesc(effectVsDesc.ShaderIndex, &effectVsDesc2);
const void *vsCodePtr = effectVsDesc2.pBytecode;
unsigned vsCodeLen = effectVsDesc2.BytecodeLength;
D3D11_INPUT_ELEMENT_DESC polygonLayout[3];
int pidx = 0;
// Create the vertex input layout description.
// This setup needs to match the VertexType stucture in the ModelClass and in the shader.
polygonLayout[pidx].SemanticName = "POSITION";
polygonLayout[pidx].SemanticIndex = 0;
polygonLayout[pidx].Format = DXGI_FORMAT_R32G32B32_FLOAT;
polygonLayout[pidx].InputSlot = 0;
polygonLayout[pidx].AlignedByteOffset = 0;
polygonLayout[pidx].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
polygonLayout[pidx].InstanceDataStepRate = 0;
pidx++;
polygonLayout[pidx].SemanticName = "DIFFUSE";
polygonLayout[pidx].SemanticIndex = 0;
polygonLayout[pidx].Format = DXGI_FORMAT_R32_UINT;
polygonLayout[pidx].InputSlot = 0;
polygonLayout[pidx].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
polygonLayout[pidx].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
polygonLayout[pidx].InstanceDataStepRate = 0;
pidx++;
polygonLayout[pidx].SemanticName = "TEXCOORD";
polygonLayout[pidx].SemanticIndex = 0;
polygonLayout[pidx].Format = DXGI_FORMAT_R32G32_FLOAT;
polygonLayout[pidx].InputSlot = 0;
polygonLayout[pidx].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
polygonLayout[pidx].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
polygonLayout[pidx].InstanceDataStepRate = 0;
pidx++;
hr = d3d->m_device->CreateInputLayout(polygonLayout, pidx, vsCodePtr, vsCodeLen, &s->layouts[idx]);
if (FAILED(hr)) {
write_log(_T("technique CreateInputLayout %08x %d\n"), hr, idx);
}
idx++;
}
return idx;
}
static bool psEffect_hasPreProcess(struct shaderdata11 *s) { return s->m_PreprocessTechnique1EffectHandle != 0; }
static bool psEffect_hasPreProcess2(struct shaderdata11 *s) { return s->m_PreprocessTechnique2EffectHandle != 0; }
static bool isws(char c)
{
return c == '\n' || c == '\r' || c == '\t' || c == ' ';
}
static bool islf(char c)
{
return c == '\n' || c == '\r' || c == ';';
}
static bool fxneedconvert(char *s)
{
char *t = s;
int len = uaestrlen(s);
while (len > 0) {
if (t != s && isws(t[-1]) && (!strnicmp(t, "technique10", 11) || !strnicmp(t, "technique11", 11)) && isws(t[11])) {
return false;
}
len--;
t++;
}
return true;
}
static void fxspecials(char *s, char *dst)
{
char *t = s;
char *d = dst;
*d = 0;
int len = uaestrlen(s);
while (len > 0) {
bool found = false;
if (t != s && !strnicmp(t, "minfilter", 9) && (isws(t[9]) || t[9] == '=') && isws(t[-1])) {
found = true;
t += 10;
len -= 10;
while (!islf(*t) && len > 0) {
if (!strnicmp(t, "point", 5)) {
strcpy(d, "Filter=MIN_MAG_MIP_POINT");
d += uaestrlen(d);
write_log("FX: 'minfilter' -> 'Filter=MIN_MAG_MIP_POINT'\n");
}
if (!strnicmp(t, "linear", 6)) {
strcpy(d, "Filter=MIN_MAG_MIP_LINEAR");
d += uaestrlen(d);
write_log("FX: 'minfiler' -> 'Filter=MIN_MAG_MIP_LINEAR'\n");
}
t++;
len--;
}
}
if (!found) {
*d++ = *t++;
len--;
}
}
*d = 0;
}
static void fxconvert(char *s, char *dst, const char **convert1, const char **convert2)
{
char *t = s;
char *d = dst;
int len = uaestrlen(s);
while (len > 0) {
bool found = false;
for (int i = 0; convert1[i]; i++) {
int slen = uaestrlen(convert1[i]);
int dlen = uaestrlen(convert2[i]);
if (len > slen && !strnicmp(t, convert1[i], slen)) {
if ((t == s || isws(t[-1])) && isws(t[slen])) {
memcpy(d, convert2[i], dlen);
t += slen;
d += dlen;
len -= slen;
found = true;
write_log("FX: '%s' -> '%s'\n", convert1[i], convert2[i]);
}
}
}
if (!found) {
*d++ = *t++;
len--;
}
}
*d = 0;
}
static void fxremoveline(char *s, char *dst, const char **lines)
{
char *t = s;
char *d = dst;
int len = uaestrlen(s);
while (len > 0) {
bool found = false;
for (int i = 0; lines[i]; i++) {
int slen = uaestrlen(lines[i]);
if (len > slen && !strnicmp(t, lines[i], slen)) {
d--;
while (d != dst) {
if (islf(*d)) {
d++;
break;
}
d--;
}
while (*t && len > 0) {
if (islf(*t)) {
t++;
len--;
break;
}
t++;
len--;
}
found = true;
write_log("FX: '%s' line removed\n", lines[i]);
}
}
if (!found) {
*d++ = *t++;
len--;
}
}
*d = 0;
}
#if 1
static bool psEffect_LoadEffect(struct d3d11struct *d3d, const TCHAR *shaderfile, struct shaderdata11 *s, int num)
{
int ret = 0;
HRESULT hr;
TCHAR tmp[MAX_DPATH];
TCHAR tmp2[MAX_DPATH], tmp3[MAX_DPATH];
static int first;
int canusefile = 0, existsfile = 0;
bool plugin_path;
struct zfile *z = NULL;
char *fx1 = NULL;
char *fx2 = NULL;
char *name = NULL;
int layout = 0;
char *fx;
int size;
if (!pD3DCompileFromFile || !ppD3DCompile) {
write_log(_T("D3D11 No shader compiler available (D3DCompiler_46.dll or D3DCompiler_47.dll).\n"));
return false;
}
DWORD dwShaderFlags = D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY;
#ifndef NDEBUG
//dwShaderFlags |= D3DCOMPILE_DEBUG;
//Disable optimizations to further improve shader debugging
//dwShaderFlags |= D3DCOMPILE_SKIP_OPTIMIZATION;
#endif
GetCurrentDirectory(MAX_DPATH, tmp3);
name = ua(shaderfile);
plugin_path = get_plugin_path(tmp2, sizeof tmp2 / sizeof(TCHAR), _T("filtershaders\\direct3d"));
_tcscpy(tmp, tmp2);
d3d->frames_since_init = 0;
if (!d3d->filenotificationhandle)
d3d->filenotificationhandle = FindFirstChangeNotification(tmp, FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE);
_tcscat(tmp, shaderfile);
write_log(_T("Direct3D11: Attempting to load '%s'\n"), tmp);
_tcscpy(s->loadedshader, shaderfile);
ID3DX11Effect *g_pEffect = NULL;
ID3DBlob *errors = NULL;
z = zfile_fopen(tmp, _T("rb"));
if (!z) {
write_log(_T("Failed to open '%s'\n"), tmp);
goto end;
}
size = zfile_size32(z);
fx1 = xcalloc(char, size * 4);
fx2 = xcalloc(char, size * 4);
if (zfile_fread(fx1, 1, size, z) != size) {
write_log(_T("Failed to read '%s'\n"), tmp);
goto end;
}
zfile_fclose(z);
z = NULL;
fx = fx1;
if (fxneedconvert(fx1)) {
static const char *converts1[] = { "technique", "vs_3_0", "vs_2_0", "vs_1_1", "ps_3_0", "ps_2_0", NULL };
static const char *converts2[] = { "technique10", "vs_4_0_level_9_3", "vs_4_0_level_9_3", "vs_4_0_level_9_3", "ps_4_0_level_9_3", "ps_4_0_level_9_3", NULL };
fxconvert(fx1, fx2, converts1, converts2);
static const char *lines[] = { "alphablendenable", "colorwriteenable", "srgbwriteenable", "magfilter", NULL };
fxremoveline(fx2, fx1, lines);
fxspecials(fx1, fx2);
fx = fx2;
}
SetCurrentDirectory(tmp2);
hr = D3DX11CompileEffectFromMemory(fx, strlen(fx), name, NULL, D3D_COMPILE_STANDARD_FILE_INCLUDE, dwShaderFlags, 0, d3d->m_device, &g_pEffect, &errors);
#if 0
hr = D3DX11CompileEffectFromFile(tmp, nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE, dwShaderFlags, 0, d3d->m_device, &g_pEffect, &errors);
#endif
if (FAILED(hr)) {
write_log(_T("Direct3D11: D3DX11CompileEffectFromMemory('%s') failed: %08x\n"), tmp, hr);
void *p = errors->GetBufferPointer();
TCHAR *s = au((char*)p);
write_log(_T("Effect compiler errors:\n%s\n"), s);
xfree(s);
goto end;
}
if (errors) {
void *p = errors->GetBufferPointer();
TCHAR *s = au((char*)p);
write_log(_T("Effect compiler warnings:\n%s\n"), s);
errors->Release();
}
if (!psEffect_ParseParameters(d3d, g_pEffect, s, name, fx, dwShaderFlags))
goto end;
SetCurrentDirectory(tmp3);
s->effect = g_pEffect;
s->CombineTechniqueEffectIndex = layout;
layout = createfxlayout(d3d, s, s->m_CombineTechniqueEffectHandle, layout);
s->PreprocessTechnique1EffectIndex = layout;
layout = createfxlayout(d3d, s, s->m_PreprocessTechnique1EffectHandle, layout);
s->PreprocessTechnique2EffectIndex = layout;
layout = createfxlayout(d3d, s, s->m_PreprocessTechnique2EffectHandle, layout);
allocfxdata(d3d, s);
createfxvertices(d3d, s);
if (s->type == SHADERTYPE_BEFORE) {
s->viewport.Width = (float)d3d->m_bitmapWidth * d3d->dmultxh;
s->viewport.Height = (float)d3d->m_bitmapHeight * d3d->dmultxv;
} else {
s->viewport.Width = (float)d3d->m_screenWidth * d3d->dmultxh;
s->viewport.Height = (float)d3d->m_screenHeight * d3d->dmultxv;
}
s->viewport.MinDepth = 0.0f;
s->viewport.MaxDepth = 1.0f;
s->viewport.TopLeftX = 0.0f;
s->viewport.TopLeftY = 0.0f;
s->psPreProcess = false;
if (psEffect_hasPreProcess(s))
s->psPreProcess = true;
xfree(fx1);
xfree(fx2);
xfree(name);
return true;
end:
SetCurrentDirectory(tmp3);
if (g_pEffect)
g_pEffect->Release();
if (errors)
errors->Release();
zfile_fclose(z);
s->loadedshader[0] = 0;
xfree(fx1);
xfree(fx2);
xfree(name);
return false;
}
#else
static bool psEffect_LoadEffect(struct d3d11struct* d3d, const TCHAR* shaderfile, struct shaderdata11* s, int num)
{
write_log(_T("FX11 disabled\n"));
return false;
}
#endif
static bool psEffect_SetMatrices(D3DXMATRIX *matProj, D3DXMATRIX *matView, D3DXMATRIX *matWorld, struct shaderdata11 *s)
{
if (s->m_MatWorldEffectHandle) {
s->m_MatWorldEffectHandle->SetMatrix((float*)matWorld);
}
if (s->m_MatViewEffectHandle) {
s->m_MatViewEffectHandle->SetMatrix((float*)matView);
}
if (s->m_MatProjEffectHandle) {
s->m_MatProjEffectHandle->SetMatrix((float*)matProj);
}
if (s->m_MatWorldViewEffectHandle) {
D3DXMATRIX matWorldView;
xD3DXMatrixMultiply(&matWorldView, matWorld, matView);
s->m_MatWorldViewEffectHandle->SetMatrix((float*)&matWorldView);
}
if (s->m_MatViewProjEffectHandle) {
D3DXMATRIX matViewProj;
xD3DXMatrixMultiply(&matViewProj, matView, matProj);
s->m_MatViewProjEffectHandle->SetMatrix((float*)&matViewProj);
}
if (s->m_MatWorldViewProjEffectHandle) {
D3DXMATRIX tmp, matWorldViewProj;
xD3DXMatrixMultiply(&tmp, matWorld, matView);
xD3DXMatrixMultiply(&matWorldViewProj, &tmp, matProj);
s->m_MatWorldViewProjEffectHandle->SetMatrix((float*)&matWorldViewProj);
}
return true;
}
static void settransform_pre(struct d3d11struct *d3d, struct shaderdata11 *s)
{
// Projection is (0,0,0) -> (1,1,1)
xD3DXMatrixOrthoOffCenterLH(&d3d->m_matProj, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
// Align texels with pixels
xD3DXMatrixTranslation(&d3d->m_matView, -0.5f / d3d->m_bitmapWidthX, 0.5f / d3d->m_bitmapHeightX, 0.0f);
// Identity for world
xD3DXMatrixIdentity(&d3d->m_matWorld);
}
static void settransform(struct d3d11struct *d3d, struct shaderdata11 *s)
{
// Projection is (0,0,0) -> (1,1,1)
xD3DXMatrixOrthoOffCenterLH(&d3d->m_matPreProj, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
// Align texels with pixels
xD3DXMatrixTranslation(&d3d->m_matPreView, -0.5f / d3d->m_bitmapWidthX, 0.5f / d3d->m_bitmapHeightX, 0.0f);
// Identity for world
xD3DXMatrixIdentity(&d3d->m_matPreWorld);
if (s)
psEffect_SetMatrices(&d3d->m_matProj, &d3d->m_matView, &d3d->m_matWorld, s);
xD3DXMatrixOrthoOffCenterLH(&d3d->m_matProj2, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
xD3DXMatrixTranslation(&d3d->m_matView2, 0.5f - 0.5f / d3d->m_bitmapWidthX, 0.5f + 0.5f / d3d->m_bitmapHeightX, 0.0f);
xD3DXMatrixIdentity(&d3d->m_matWorld2);
}
static void settransform2(struct d3d11struct *d3d, struct shaderdata11 *s)
{
// Projection is (0,0,0) -> (1,1,1)
xD3DXMatrixOrthoOffCenterLH(&d3d->m_matPreProj, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
// Align texels with pixels
xD3DXMatrixTranslation(&d3d->m_matPreView, -0.5f / d3d->m_screenWidth, 0.5f / d3d->m_screenHeight, 0.0f);
// Identity for world
xD3DXMatrixIdentity(&d3d->m_matPreWorld);
xD3DXMatrixOrthoOffCenterLH(&d3d->m_matProj2, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
xD3DXMatrixTranslation(&d3d->m_matView2, 0.5f - 0.5f / d3d->m_screenWidth, 0.5f + 0.5f / d3d->m_screenHeight, 0.0f);
xD3DXMatrixIdentity(&d3d->m_matWorld2);
}
static int psEffect_SetTextures(ID3D11Texture2D *lpSourceTex, ID3D11ShaderResourceView *lpSourcerv, struct shaderdata11 *s)
{
D3DXVECTOR4 fDims, fTexelSize;
if (!s->m_SourceTextureEffectHandle) {
write_log(_T("D3D11 Texture with SOURCETEXTURE semantic not found\n"));
return 0;
}
s->m_SourceTextureEffectHandle->SetResource(lpSourcerv);
if (s->m_WorkingTexture1EffectHandle) {
s->m_WorkingTexture1EffectHandle->SetResource(s->lpWorkTexture1.rv);
}
if (s->m_WorkingTexture2EffectHandle) {
s->m_WorkingTexture2EffectHandle->SetResource(s->lpWorkTexture2.rv);
}
if (s->m_Hq2xLookupTextureHandle) {
s->m_Hq2xLookupTextureHandle->SetResource(s->lpHq2xLookupTexturerv);
}
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 (lpSourceTex) {
D3D11_TEXTURE2D_DESC desc;
lpSourceTex->GetDesc(&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) {
s->m_SourceDimsEffectHandle->SetFloatVector((float*)&fDims);
}
if (s->m_InputDimsEffectHandle) {
s->m_InputDimsEffectHandle->SetFloatVector((float*)&fDims);
}
if (s->m_TargetDimsEffectHandle) {
D3DXVECTOR4 fDimsTarget;
fDimsTarget.x = (float)s->targettex_width;
fDimsTarget.y = (float)s->targettex_height;
fDimsTarget.z = 1;
fDimsTarget.w = 1;
s->m_TargetDimsEffectHandle->SetFloatVector((float*)&fDimsTarget);
}
if (s->m_TexelSizeEffectHandle) {
s->m_TexelSizeEffectHandle->SetFloatVector((float*)&fTexelSize);
}
if (s->m_ScaleEffectHandle) {
D3DXVECTOR4 fScale;
fScale.x = (float)(1 << currprefs.gfx_resolution);
fScale.y = (float)(1 << currprefs.gfx_vresolution);
fScale.w = fScale.z = 1;
s->m_ScaleEffectHandle->SetFloatVector((float*)&fScale);
}
if (s->framecounterHandle) {
s->framecounterHandle->SetFloat((float)vsync_counter);
}
return 1;
}
enum psEffect_Pass { psEffect_None, psEffect_PreProcess1, psEffect_PreProcess2, psEffect_Combine };
static bool psEffect_Begin(struct d3d11struct *d3d, enum psEffect_Pass pass, int *pPasses, int *pIndex, struct shaderdata11 *s)
{
ID3DX11Effect *effect = s->effect;
D3DX11_TECHNIQUE_DESC desc;
int idx = 0;
d3d->technique = NULL;
switch (pass)
{
case psEffect_PreProcess1:
d3d->technique = s->m_PreprocessTechnique1EffectHandle;
*pIndex = s->PreprocessTechnique1EffectIndex;
break;
case psEffect_PreProcess2:
d3d->technique = s->m_PreprocessTechnique2EffectHandle;
*pIndex = s->PreprocessTechnique2EffectIndex;
break;
case psEffect_Combine:
d3d->technique = s->m_CombineTechniqueEffectHandle;
*pIndex = s->CombineTechniqueEffectIndex;
break;
}
if (!d3d->technique)
return false;
HRESULT hr = d3d->technique->GetDesc(&desc);
if (FAILED(hr)) {
write_log(_T("technique->GetDesc %08x\n"), hr);
return false;
}
*pPasses = desc.Passes;
return true;
}
static bool psEffect_BeginPass(struct d3d11struct *d3d, struct shaderdata11 *s, int Pass, int Index)
{
ID3DX11EffectPass *effectpass = d3d->technique->GetPassByIndex(Pass);
if (!effectpass->IsValid()) {
write_log(_T("psEffect_BeginPass pass %d not valid\n"), Pass);
return false;
}
d3d->effectpass = effectpass;
HRESULT hr = effectpass->Apply(0, d3d->m_deviceContext);
if (FAILED(hr)) {
write_log(_T("effectpass->Apply %08x\n"), hr);
}
UINT stride = sizeof(TLVERTEX);
UINT offset = 0;
d3d->m_deviceContext->IASetVertexBuffers(0, 1, &s->vertexBuffer, &stride, &offset);
d3d->m_deviceContext->IASetIndexBuffer(s->indexBuffer, d3d->index_buffer_bytes == 4 ? DXGI_FORMAT_R32_UINT : DXGI_FORMAT_R16_UINT, 0);
d3d->m_deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
d3d->m_deviceContext->IASetInputLayout(s->layouts[Index + Pass]);
return true;
}
static bool psEffect_EndPass(struct d3d11struct *d3d, struct shaderdata11 *s)
{
d3d->technique = NULL;
d3d->effectpass = NULL;
return true;
}
static bool psEffect_End(struct d3d11struct *d3d, struct shaderdata11 *s)
{
return true;
}
static bool processshader(struct d3d11struct *d3d, struct shadertex *st, struct shaderdata11 *s, bool rendertarget)
{
int uPasses, uPass, uIndex;
ID3D11RenderTargetView *lpRenderTarget = NULL;
ID3D11RenderTargetView *lpNewRenderTarget;
struct shadertex *lpWorkTexture;
d3d->m_deviceContext->RSSetViewports(1, st->vp);
TurnOffAlphaBlending(d3d);
if (!psEffect_SetTextures(st->tex, st->rv, s))
return NULL;
if (s->psPreProcess) {
if (!psEffect_SetMatrices(&d3d->m_matPreProj, &d3d->m_matPreView, &d3d->m_matPreWorld, s))
return NULL;
d3d->m_deviceContext->OMGetRenderTargets(1, &lpRenderTarget, NULL);
lpWorkTexture = &s->lpWorkTexture1;
lpNewRenderTarget = lpWorkTexture->rt;
d3d->m_deviceContext->OMSetRenderTargets(1, &lpNewRenderTarget, NULL);
pass2:
uPasses = 0;
if (psEffect_Begin(d3d, (lpWorkTexture == &s->lpWorkTexture1) ? psEffect_PreProcess1 : psEffect_PreProcess2, &uPasses, &uIndex, s)) {
for (uPass = 0; uPass < uPasses; uPass++) {
if (psEffect_BeginPass(d3d, s, uPass, uIndex)) {
d3d->m_deviceContext->DrawIndexed(6, 6, 0);
psEffect_EndPass(d3d, s);
}
}
psEffect_End(d3d, s);
}
if (lpRenderTarget) {
d3d->m_deviceContext->OMSetRenderTargets(1, &lpRenderTarget, NULL);
}
lpNewRenderTarget = NULL;
if (psEffect_hasPreProcess2(s) && lpWorkTexture == &s->lpWorkTexture1) {
lpWorkTexture = &s->lpWorkTexture2;
goto pass2;
}
if (lpRenderTarget) {
lpRenderTarget->Release();
lpRenderTarget = NULL;
}
}
psEffect_SetMatrices(&d3d->m_matProj2, &d3d->m_matView2, &d3d->m_matWorld2, s);
if (rendertarget) {
d3d->m_deviceContext->OMGetRenderTargets(1, &lpRenderTarget, NULL);
d3d->m_deviceContext->OMSetRenderTargets(1, &s->lpTempTexture.rt, NULL);
}
TurnOffAlphaBlending(d3d);
uPasses = 0;
if (psEffect_Begin(d3d, psEffect_Combine, &uPasses, &uIndex, s)) {
for (uPass = 0; uPass < uPasses; uPass++) {
if (!psEffect_BeginPass(d3d, s, uPass, uIndex)) {
if (lpRenderTarget) {
lpRenderTarget->Release();
}
return false;
}
d3d->m_deviceContext->DrawIndexed(6, 0, 0);
psEffect_EndPass(d3d, s);
}
psEffect_End(d3d, s);
}
if (rendertarget) {
d3d->m_deviceContext->OMSetRenderTargets(1, &lpRenderTarget, NULL);
}
if (lpRenderTarget) {
lpRenderTarget->Release();
}
memcpy(st, &s->lpTempTexture, sizeof(struct shadertex));
return true;
}
static bool UpdateVertexArray(struct d3d11struct *d3d, ID3D11Buffer *vertexbuffer,
float left, float top, float right, float bottom,
float slleft, float sltop, float slright, float slbottom)
{
VertexType* verticesPtr;
D3D11_MAPPED_SUBRESOURCE mappedResource;
HRESULT result;
VertexType vertices[4];
if (!vertexbuffer)
return false;
// Load the vertex array with data.
vertices[0].position = D3DXVECTOR3(left, top, 0.0f); // Top left.
vertices[0].texture = D3DXVECTOR2(0.0f, 0.0f);
vertices[0].sltexture = D3DXVECTOR2(slleft, sltop);
vertices[1].position = D3DXVECTOR3(right, top, 0.0f); // Top right.
vertices[1].texture = D3DXVECTOR2(1.0f, 0.0f);
vertices[1].sltexture = D3DXVECTOR2(slright, sltop);
vertices[2].position = D3DXVECTOR3(right, bottom, 0.0f); // Bottom right.
vertices[2].texture = D3DXVECTOR2(1.0f, 1.0f);
vertices[2].sltexture = D3DXVECTOR2(slright, slbottom);
vertices[3].position = D3DXVECTOR3(left, bottom, 0.0f); // Bottom left.
vertices[3].texture = D3DXVECTOR2(0.0f, 1.0f);
vertices[3].sltexture = D3DXVECTOR2(slleft, slbottom);
// Lock the vertex buffer so it can be written to.
result = d3d->m_deviceContext->Map(vertexbuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
if (FAILED(result))
{
write_log(_T("ID3D11DeviceContext map(vertex) %08x\n"), result);
return false;
}
// Get a pointer to the data in the vertex buffer.
verticesPtr = (VertexType*)mappedResource.pData;
// Copy the data into the vertex buffer.
memcpy(verticesPtr, (void*)vertices, (sizeof(VertexType) * VERTEXCOUNT));
// Unlock the vertex buffer.
d3d->m_deviceContext->Unmap(vertexbuffer, 0);
return true;
}
static bool UpdateBuffers(struct d3d11struct *d3d, int monid)
{
int bw = d3d->m_bitmapWidth;
int bh = d3d->m_bitmapHeight;
int sw = d3d->m_screenWidth;
int sh = d3d->m_screenHeight;
float positionX = d3d->xoffset;
float positionY = -d3d->yoffset;
float slleft = 0;
float sltop = 0;
float slright = (float)bw * d3d->xmult / sw;
float slbottom = (float)bh * d3d->ymult / sh;
slright = slleft + slright;
slbottom = sltop + slbottom;
float rot = get_rotation(d3d, monid);
D3DXMATRIX scaling, rotation, translation, worldMatrix;
xD3DXMatrixScaling(&scaling, bw * d3d->xmult, bh * d3d->ymult, 1.0f);
xD3DXMatrixRotationZ(&rotation, rot);
xD3DXMatrixTranslation(&translation, positionX, positionY, 0.0f);
xD3DXMatrixMultiply(&worldMatrix, &scaling, &rotation);
xD3DXMatrixMultiply(&worldMatrix, &worldMatrix, &translation);
d3d->m_worldMatrix = worldMatrix;
UpdateVertexArray(d3d, d3d->m_vertexBuffer, -0.5f, 0.5f, 0.5f, -0.5f, slleft, sltop, slright, slbottom);
return true;
}
static void setupscenecoords(struct d3d11struct *d3d, bool normalrender, int monid)
{
RECT sr, dr, zr;
static RECT sr2[MAX_AMIGAMONITORS], dr2[MAX_AMIGAMONITORS], zr2[MAX_AMIGAMONITORS];
if (!normalrender)
return;
getfilterrect2(d3d->num, &dr, &sr, &zr, d3d->m_screenWidth, d3d->m_screenHeight, d3d->m_bitmapWidth / d3d->dmult, d3d->m_bitmapHeight / d3d->dmult, d3d->dmult, &d3d->dmode, d3d->m_bitmapWidth, d3d->m_bitmapHeight);
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) S=%d*%d B=%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,
d3d->m_screenWidth, d3d->m_screenHeight,
d3d->m_bitmapWidth, d3d->m_bitmapHeight);
sr2[monid] = sr;
dr2[monid] = dr;
zr2[monid] = zr;
}
d3d->sr2 = sr;
d3d->dr2 = dr;
d3d->zr2 = zr;
float dw = (float)dr.right - dr.left;
float dh = (float)dr.bottom - dr.top;
float w = (float)sr.right - sr.left;
float h = (float)sr.bottom - sr.top;
int tx = ((dr.right - dr.left) * d3d->m_bitmapWidth) / (d3d->m_screenWidth * 2);
int ty = ((dr.bottom - dr.top) * d3d->m_bitmapHeight) / (d3d->m_screenHeight * 2);
float sw = dw / d3d->m_screenWidth;
float sh = dh / d3d->m_screenHeight;
int xshift = -zr.left - sr.left;
int yshift = -zr.top - sr.top;
xshift -= ((sr.right - sr.left) - d3d->m_screenWidth) / 2;
yshift -= ((sr.bottom - sr.top) - d3d->m_screenHeight) / 2;
d3d->xoffset = (float)tx + xshift - d3d->m_screenWidth / 2.0f;
d3d->yoffset = (float)ty + yshift - d3d->m_screenHeight / 2.0f;
d3d->xmult = filterrectmult(d3d->m_screenWidth, w, d3d->dmode);
d3d->ymult = filterrectmult(d3d->m_screenHeight, h, d3d->dmode);
d3d->xoffset *= d3d->xmult;
d3d->yoffset *= d3d->ymult;
d3d->cursor_offset_x = -zr.left;
d3d->cursor_offset_y = -zr.top;
UpdateBuffers(d3d, monid);
xD3DXMatrixOrthoOffCenterLH(&d3d->m_matProj_out, 0, w + 0.05f, 0, h + 0.05f, 0.0f, 1.0f);
xD3DXMatrixTranslation(&d3d->m_matView_out, (float)tx, (float)ty, 1.0f);
sw *= d3d->m_bitmapWidth;
sh *= d3d->m_bitmapHeight;
xD3DXMatrixScaling(&d3d->m_matWorld_out, sw + 0.5f / sw, sh + 0.5f / sh, 1.0f);
}
static void updateleds(struct d3d11struct *d3d)
{
HRESULT hr;
D3D11_MAPPED_SUBRESOURCE map;
static uae_u32 rc[256], gc[256], bc[256], a[256];
static int done;
int osdx, osdy;
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->osd.texture || d3d != d3d11data)
return;
statusline_getpos(d3d->num, &osdx, &osdy, d3d->m_screenWidth, d3d->m_screenHeight);
d3d->osd.x = (float)osdx;
d3d->osd.y = (float)osdy;
hr = d3d->m_deviceContext->Map(d3d->osd.texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
if (FAILED(hr)) {
write_log(_T("Led Map failed %08x\n"), hr);
return;
}
for (int y = 0; y < d3d->osd.height; y++) {
uae_u8 *buf = (uae_u8*)map.pData + y * map.RowPitch;
statusline_single_erase(d3d->num, buf, 32 / 8, y, d3d->ledwidth);
}
statusline_render(d3d->num, (uae_u8*)map.pData, 32 / 8, map.RowPitch, d3d->ledwidth, d3d->ledheight, rc, gc, bc, a);
for (int y = 0; y < d3d->osd.height; y++) {
uae_u8 *buf = (uae_u8*)map.pData + y * map.RowPitch;
draw_status_line_single(d3d->num, buf, 32 / 8, y, d3d->ledwidth, rc, gc, bc, a);
}
d3d->m_deviceContext->Unmap(d3d->osd.texture, 0);
}
static bool createvertexshader(struct d3d11struct *d3d, ID3D11VertexShader **vertexshader, ID3D11Buffer **matrixbuffer, ID3D11InputLayout **layout)
{
D3D11_INPUT_ELEMENT_DESC polygonLayout[3];
HRESULT hr;
unsigned int numElements;
D3D11_BUFFER_DESC matrixBufferDesc;
// Create the vertex shader from the buffer.
hr = d3d->m_device->CreateVertexShader(VertexShader, sizeof(VertexShader), NULL, vertexshader);
if (FAILED(hr))
{
write_log(_T("ID3D11Device CreateVertexShader %08x\n"), hr);
return false;
}
#ifndef NDEBUG
static const char vname[] = "vertexbuffer";
(*vertexshader)->SetPrivateData(WKPDID_D3DDebugObjectName, sizeof(vname) - 1, vname);
#endif
// Create the vertex input layout description.
// This setup needs to match the VertexType stucture in the ModelClass and in the shader.
polygonLayout[0].SemanticName = "POSITION";
polygonLayout[0].SemanticIndex = 0;
polygonLayout[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
polygonLayout[0].InputSlot = 0;
polygonLayout[0].AlignedByteOffset = 0;
polygonLayout[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
polygonLayout[0].InstanceDataStepRate = 0;
polygonLayout[1].SemanticName = "TEXCOORD";
polygonLayout[1].SemanticIndex = 0;
polygonLayout[1].Format = DXGI_FORMAT_R32G32_FLOAT;
polygonLayout[1].InputSlot = 0;
polygonLayout[1].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
polygonLayout[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
polygonLayout[1].InstanceDataStepRate = 0;
polygonLayout[2].SemanticName = "TEXCOORD";
polygonLayout[2].SemanticIndex = 1;
polygonLayout[2].Format = DXGI_FORMAT_R32G32_FLOAT;
polygonLayout[2].InputSlot = 0;
polygonLayout[2].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
polygonLayout[2].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
polygonLayout[2].InstanceDataStepRate = 0;
// Get a count of the elements in the layout.
numElements = sizeof(polygonLayout) / sizeof(polygonLayout[0]);
// Create the vertex input layout.
hr = d3d->m_device->CreateInputLayout(polygonLayout, numElements, VertexShader, sizeof(VertexShader), layout);
if (FAILED(hr))
{
write_log(_T("ID3D11Device CreateInputLayout %08x\n"), hr);
return false;
}
// Setup the description of the dynamic matrix constant buffer that is in the vertex shader.
matrixBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
matrixBufferDesc.ByteWidth = sizeof(MatrixBufferType);
matrixBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
matrixBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
matrixBufferDesc.MiscFlags = 0;
matrixBufferDesc.StructureByteStride = 0;
// Create the constant buffer pointer so we can access the vertex shader constant buffer from within this class.
hr = d3d->m_device->CreateBuffer(&matrixBufferDesc, NULL, matrixbuffer);
if (FAILED(hr))
{
write_log(_T("ID3D11Device CreateBuffer(matrix) %08x\n"), hr);
return false;
}
#ifndef NDEBUG
static const char mname[] = "matrixbuffer";
(*matrixbuffer)->SetPrivateData(WKPDID_D3DDebugObjectName, sizeof(mname) - 1, mname);
#endif
return true;
}
static void FreeTexture2D(ID3D11Texture2D **t, ID3D11ShaderResourceView **v)
{
if (t && *t) {
(*t)->Release();
(*t) = NULL;
}
if (v && *v) {
(*v)->Release();
(*v) = NULL;
}
}
static void freesprite(struct d3d11sprite *s)
{
if (!s)
return;
FreeTexture2D(&s->texture, &s->texturerv);
if (s->pixelshader)
s->pixelshader->Release();
if (s->vertexshader)
s->vertexshader->Release();
if (s->layout)
s->layout->Release();
if (s->vertexbuffer)
s->vertexbuffer->Release();
if (s->indexbuffer)
s->indexbuffer->Release();
if (s->matrixbuffer)
s->matrixbuffer->Release();
if (s->texbuf)
xfree(s->texbuf);
memset(s, 0, sizeof(struct d3d11sprite));
}
static void FreeShaderTex(struct shadertex *t)
{
FreeTexture2D(&t->tex, &t->rv);
if (t->rt)
t->rt->Release();
t->rt = NULL;
}
static void freeshaderdata(struct shaderdata11 *s)
{
if (s->effect) {
s->effect->Release();
s->effect = NULL;
}
FreeTexture2D(&s->masktexture, &s->masktexturerv);
FreeShaderTex(&s->lpWorkTexture1);
FreeShaderTex(&s->lpWorkTexture2);
FreeShaderTex(&s->lpTempTexture);
if (s->lpHq2xLookupTexture) {
s->lpHq2xLookupTexture->Release();
s->lpHq2xLookupTexture = NULL;
}
if (s->lpHq2xLookupTexturerv) {
s->lpHq2xLookupTexturerv->Release();
s->lpHq2xLookupTexturerv = NULL;
}
for (int j = 0; j < MAX_TECHNIQUE_LAYOUTS; j++) {
if (s->layouts[j])
s->layouts[j]->Release();
s->layouts[j] = NULL;
}
if (s->vertexBuffer) {
s->vertexBuffer->Release();
s->vertexBuffer = NULL;
}
if (s->indexBuffer) {
s->indexBuffer->Release();
s->indexBuffer = NULL;
}
memset(s, 0, sizeof(struct shaderdata11));
}
static void FreeTextures(struct d3d11struct *d3d)
{
FreeTexture2D(&d3d->texture2d, &d3d->texture2drv);
FreeTexture2D(&d3d->texture2dstaging, NULL);
FreeTexture2D(&d3d->screenshottexturetx, NULL);
FreeTexture2D(&d3d->screenshottexturert, NULL);
freesprite(&d3d->osd);
freesprite(&d3d->hwsprite);
freesprite(&d3d->mask2texture);
for (int i = 0; overlayleds[i]; i++) {
freesprite(&d3d->mask2textureleds[i]);
}
freesprite(&d3d->mask2textureled_power_dim);
freesprite(&d3d->blanksprite);
struct d3doverlay *ov = d3d->extoverlays;
while (ov) {
struct d3doverlay *next = ov->next;
freesprite(&ov->s);
xfree(ov);
ov = next;
}
d3d->extoverlays = NULL;
for (int i = 0; i < MAX_SHADERS; i++) {
freeshaderdata(&d3d->shaders[i]);
}
}
static bool InitializeBuffers(struct d3d11struct *d3d, ID3D11Buffer **vertexBuffer, ID3D11Buffer **indexBuffer)
{
D3D11_BUFFER_DESC vertexBufferDesc, indexBufferDesc;
D3D11_SUBRESOURCE_DATA vertexData, indexData;
HRESULT result;
VertexType vertices[VERTEXCOUNT];
uae_u32 indices[INDEXCOUNT];
d3d->index_buffer_bytes = d3d11_feature_level >= D3D10_FEATURE_LEVEL_9_2 ? sizeof(uae_u32) : sizeof(uae_u16);
// Initialize vertex array to zeros at first.
memset(vertices, 0, (sizeof(VertexType) * VERTEXCOUNT));
static const uae_u16 indexes[6] = { 0, 2, 1, 2, 0, 3 };
// Load the index array with data.
for (int i = 0; i < INDEXCOUNT; i++)
{
if (d3d->index_buffer_bytes == 4)
((uae_u32*)indices)[i] = indexes[i];
else
((uae_u16*)indices)[i] = indexes[i];
}
// Set up the description of the static vertex buffer.
vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
vertexBufferDesc.ByteWidth = sizeof(VertexType) * VERTEXCOUNT;
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
vertexBufferDesc.MiscFlags = 0;
vertexBufferDesc.StructureByteStride = 0;
// Give the subresource structure a pointer to the vertex data.
vertexData.pSysMem = vertices;
vertexData.SysMemPitch = 0;
vertexData.SysMemSlicePitch = 0;
// Now create the vertex buffer.
result = d3d->m_device->CreateBuffer(&vertexBufferDesc, &vertexData, vertexBuffer);
if (FAILED(result))
{
write_log(_T("ID3D11Device CreateBuffer(vertex) %08x\n"), result);
return false;
}
#ifndef NDEBUG
static const char vname[] = "mvertexbuffer";
(*vertexBuffer)->SetPrivateData(WKPDID_D3DDebugObjectName, sizeof(vname) - 1, vname);
#endif
// Set up the description of the static index buffer.
indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
indexBufferDesc.ByteWidth = d3d->index_buffer_bytes * INDEXCOUNT;
indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
indexBufferDesc.CPUAccessFlags = 0;
indexBufferDesc.MiscFlags = 0;
indexBufferDesc.StructureByteStride = 0;
// Give the subresource structure a pointer to the index data.
indexData.pSysMem = indices;
indexData.SysMemPitch = 0;
indexData.SysMemSlicePitch = 0;
// Create the index buffer.
result = d3d->m_device->CreateBuffer(&indexBufferDesc, &indexData, indexBuffer);
if (FAILED(result))
{
write_log(_T("ID3D11Device CreateBuffer(index) %08x\n"), result);
return false;
}
#ifndef NDEBUG
static const char iname[] = "mindexbuffer";
(*indexBuffer)->SetPrivateData(WKPDID_D3DDebugObjectName, sizeof(iname) - 1, iname);
#endif
return true;
}
static void setsprite(struct d3d11struct *d3d, struct d3d11sprite *s, float x, float y)
{
s->x = x;
s->y = y;
}
static bool allocsprite(struct d3d11struct *d3d, struct d3d11sprite *s, int width, int height, bool alpha, bool rotation, bool screenlimit)
{
D3D11_TEXTURE2D_DESC desc;
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
HRESULT hr;
freesprite(s);
s->width = width;
s->height = height;
s->alpha = alpha;
s->rotation = rotation;
s->screenlimit = screenlimit;
s->empty = true;
if (screenlimit) {
s->texbuf = xcalloc(uae_u8, width * height * 4);
if (!s->texbuf) {
return false;
}
}
if (!InitializeBuffers(d3d, &s->vertexbuffer, &s->indexbuffer))
goto err;
if (gfx_hdr) {
hr = d3d->m_device->CreatePixelShader(PS_PostPlain_HDR, sizeof(PS_PostPlain_HDR), NULL, &s->pixelshader);
} else {
hr = d3d->m_device->CreatePixelShader(PS_PostPlain, sizeof(PS_PostPlain), NULL, &s->pixelshader);
}
if (FAILED(hr))
goto err;
if (!createvertexshader(d3d, &s->vertexshader, &s->matrixbuffer, &s->layout))
goto err;
memset(&desc, 0, sizeof desc);
desc.Width = s->width;
desc.Height = s->height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = d3d->texformat;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
hr = d3d->m_device->CreateTexture2D(&desc, NULL, &s->texture);
if (FAILED(hr)) {
write_log(_T("CreateTexture2D (%dx%d) failed: %08x\n"), width, height, hr);
goto err;
}
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Texture2D.MipLevels = desc.MipLevels;
srvDesc.Format = d3d->texformat;
hr = d3d->m_device->CreateShaderResourceView(s->texture, &srvDesc, &s->texturerv);
if (FAILED(hr)) {
write_log(_T("CreateShaderResourceView (%dx%d) failed: %08x\n"), width, height, hr);
goto err;
}
setsprite(d3d, s, 0, 0);
return true;
err:
freesprite(s);
return false;
}
#if 0
static void erasetexture(struct d3d11struct *d3d)
{
int pitch;
uae_u8 *p = D3D_locktexture(d3d->num, &pitch, NULL, true);
if (p) {
for (int i = 0; i < d3d->m_bitmapHeight; i++) {
memset(p, 255, d3d->m_bitmapWidth * d3d->texdepth / 8);
p += pitch;
}
D3D_unlocktexture(d3d->num, -1, -1);
}
}
#endif
static bool CreateTexture(struct d3d11struct *d3d)
{
struct AmigaMonitor *mon = &AMonitors[d3d->num];
D3D11_TEXTURE2D_DESC desc;
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
HRESULT hr;
memset(&d3d->sr2, 0, sizeof(RECT));
memset(&d3d->dr2, 0, sizeof(RECT));
memset(&d3d->zr2, 0, sizeof(RECT));
FreeTextures(d3d);
memset(&desc, 0, sizeof desc);
desc.Width = d3d->m_bitmapWidth;
desc.Height = d3d->m_bitmapHeight;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = d3d->texformat;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
hr = d3d->m_device->CreateTexture2D(&desc, NULL, &d3d->texture2d);
if (FAILED(hr)) {
write_log(_T("CreateTexture2D (main) failed: %08x\n"), hr);
return false;
}
memset(&desc, 0, sizeof desc);
desc.Width = d3d->m_bitmapWidth;
desc.Height = d3d->m_bitmapHeight;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = d3d->texformat;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_STAGING;
desc.BindFlags = 0;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
hr = d3d->m_device->CreateTexture2D(&desc, NULL, &d3d->texture2dstaging);
if (FAILED(hr)) {
write_log(_T("CreateTexture2D (staging) failed: %08x\n"), hr);
return false;
}
desc.Width = d3d->m_bitmapWidth;
desc.Height = d3d->m_bitmapHeight;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
hr = d3d->m_device->CreateTexture2D(&desc, nullptr, &d3d->screenshottexturetx);
if (FAILED(hr)) {
write_log(_T("CreateTexture2D (screenshot tx) failed: %08x\n"), hr);
}
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Texture2D.MipLevels = desc.MipLevels;
srvDesc.Format = d3d->texformat;
hr = d3d->m_device->CreateShaderResourceView(d3d->texture2d, &srvDesc, &d3d->texture2drv);
if (FAILED(hr)) {
write_log(_T("CreateShaderResourceView MAIN failed: %08x\n"), hr);
return false;
}
ID3D11Texture2D *pSurface;
hr = d3d->m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&pSurface));
if (SUCCEEDED(hr)) {
memset(&desc, 0, sizeof desc);
pSurface->GetDesc(&desc);
desc.BindFlags = 0;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.Usage = D3D11_USAGE_STAGING;
hr = d3d->m_device->CreateTexture2D(&desc, nullptr, &d3d->screenshottexturert);
if (FAILED(hr)) {
write_log(_T("CreateTexture2D (screenshot rt) failed: %08x\n"), hr);
}
pSurface->Release();
}
UpdateVertexArray(d3d, d3d->m_vertexBuffer, 0, 0, 0, 0, 0, 0, 0, 0);
d3d->statusbar_hx = d3d->statusbar_vx = statusline_set_multiplier(mon->monitor_id, d3d->m_screenWidth, d3d->m_screenHeight) / 100;
d3d->ledwidth = d3d->m_screenWidth;
d3d->ledheight = TD_TOTAL_HEIGHT * d3d->statusbar_vx;
allocsprite(d3d, &d3d->osd, d3d->ledwidth, d3d->ledheight, true, false, false);
d3d->osd.enabled = true;
d3d->cursor_v = false;
d3d->cursor_scale = false;
allocsprite(d3d, &d3d->hwsprite, CURSORMAXWIDTH, CURSORMAXHEIGHT, true, true, true);
write_log(_T("D3D11 %dx%d main texture allocated\n"), d3d->m_bitmapWidth, d3d->m_bitmapHeight);
return true;
}
static bool allocshadertex(struct d3d11struct *d3d, struct shadertex *t, int w, int h, int idx)
{
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
D3D11_TEXTURE2D_DESC desc;
HRESULT hr;
memset(&desc, 0, sizeof desc);
desc.Width = w;
desc.Height = h;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = d3d->scrformat;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
desc.CPUAccessFlags = 0;
hr = d3d->m_device->CreateTexture2D(&desc, NULL, &t->tex);
if (FAILED(hr)) {
write_log(_T("D3D11 Failed to create working texture: %08x:%d\n"), hr, idx);
return 0;
}
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Texture2D.MipLevels = desc.MipLevels;
srvDesc.Format = d3d->scrformat;
hr = d3d->m_device->CreateShaderResourceView(t->tex, &srvDesc, &t->rv);
if (FAILED(hr)) {
write_log(_T("CreateShaderResourceView texture failed: %08x:%d\n"), hr, idx);
return false;
}
hr = d3d->m_device->CreateRenderTargetView(t->tex, NULL, &t->rt);
if (FAILED(hr))
{
write_log(_T("ID3D11Device CreateRenderTargetView %08x:%d\n"), hr, idx);
return false;
}
return true;
}
static bool allocextratextures(struct d3d11struct *d3d, struct shaderdata11 *s, int w, int h)
{
int scnt = addrdiff(s, &d3d->shaders[0]);
if (!allocshadertex(d3d, &s->lpWorkTexture1, w, h, scnt))
return false;
if (!allocshadertex(d3d, &s->lpWorkTexture2, w, h, scnt))
return false;
write_log(_T("D3D11 %d*%d working texture:%d\n"), w, h, scnt);
return true;
}
static bool createextratextures(struct d3d11struct *d3d, int ow, int oh, int win_w, int win_h)
{
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++) {
struct shaderdata11 *s = &d3d->shaders[i];
if (s->type == SHADERTYPE_BEFORE || s->type == SHADERTYPE_AFTER || s->type == SHADERTYPE_MIDDLE) {
int w2, h2, w, h;
if (s->type == SHADERTYPE_AFTER) {
w2 = zw; h2 = zh;
w = zw; h = zh;
haveafter = true;
if (!allocextratextures(d3d, &d3d->shaders[i], d3d->m_screenWidth, d3d->m_screenHeight))
return 0;
} else if (s->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 (!allocshadertex(d3d, &s->lpTempTexture, w2, h2, (int)(s - &d3d->shaders[0])))
return false;
write_log(_T("D3D11 %d*%d temp texture:%d:%d\n"), w2, h2, i, d3d->shaders[i].type);
d3d->shaders[i].worktex_width = w;
d3d->shaders[i].worktex_height = h;
}
}
if (haveafter) {
if (!allocshadertex(d3d, &d3d->lpPostTempTexture, d3d->m_screenWidth, d3d->m_screenHeight, -1))
return 0;
write_log(_T("D3D11 %d*%d after texture\n"), d3d->m_screenWidth, d3d->m_screenHeight);
}
return 1;
}
static bool createsltexture(struct d3d11struct *d3d)
{
D3D11_TEXTURE2D_DESC desc;
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
HRESULT hr;
FreeTexture2D(&d3d->sltexture, &d3d->sltexturerv);
memset(&desc, 0, sizeof desc);
desc.Width = d3d->m_screenWidth;
desc.Height = d3d->m_screenHeight;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = d3d->texformat;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
hr = d3d->m_device->CreateTexture2D(&desc, NULL, &d3d->sltexture);
if (FAILED(hr)) {
write_log(_T("CreateTexture2D (main) failed: %08x\n"), hr);
return false;
}
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Texture2D.MipLevels = desc.MipLevels;
srvDesc.Format = d3d->texformat;
hr = d3d->m_device->CreateShaderResourceView(d3d->sltexture, &srvDesc, &d3d->sltexturerv);
if (FAILED(hr)) {
write_log(_T("CreateShaderResourceView SL failed: %08x\n"), hr);
FreeTexture2D(&d3d->sltexture, NULL);
return false;
}
write_log(_T("SL %d*%d texture allocated\n"), desc.Width, desc.Height);
return true;
}
static void createscanlines(struct d3d11struct *d3d, int force)
{
HRESULT hr;
D3D11_MAPPED_SUBRESOURCE map;
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 = 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->m_deviceContext->Map(d3d->sltexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
if (FAILED(hr)) {
write_log(_T("SL Map failed %08x\n"), hr);
return;
}
sld = (uae_u8*)map.pData;
for (y = 0; y < d3d->m_screenHeight; y++) {
memset(sld + y * map.RowPitch, 0, d3d->m_screenWidth * bpp);
}
for (y = 0; y < d3d->m_screenHeight; y += l1 + l2) {
int y2 = y + (d3d->filterd3d->gfx_filter_scanlineoffset % (l1 + 1));
for (yy = 0; yy < l2 && y2 + yy < d3d->m_screenHeight; yy++) {
for (x = 0; x < d3d->m_screenWidth; x++) {
uae_u8 sll = sl42;
p = &sld[(y2 + yy) * map.RowPitch + (x * bpp)];
/* 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->m_deviceContext->Unmap(d3d->sltexture, 0);
}
#include "png.h"
#include <atlcomcli.h>
struct uae_image
{
uae_u8 *data;
int width, height, pitch;
};
struct png_cb
{
uae_u8 *ptr;
size_t 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 d3d11struct *d3d, const TCHAR *filename)
{
struct AmigaMonitor *mon = &AMonitors[d3d->num];
struct zfile *zf;
TCHAR tmp[MAX_DPATH];
ID3D11Texture2D *tx = NULL;
HRESULT hr;
TCHAR filepath[MAX_DPATH];
float xmult, ymult;
freesprite(&d3d->mask2texture);
for (int i = 0; overlayleds[i]; i++) {
freesprite(&d3d->mask2textureleds[i]);
}
freesprite(&d3d->mask2textureled_power_dim);
freesprite(&d3d->blanksprite);
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->m_screenWidth, d3d->m_screenHeight, tmp2);
_tcscpy(filepath, tmp3);
zf = zfile_fopen(tmp3, _T("rb"), ZFD_NORMAL);
if (zf)
break;
float aspect = (float)d3d->m_screenWidth / d3d->m_screenHeight;
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("Couldn't open overlay '%s'\n"), 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;
}
d3d->mask2texture_w = (float)img.width;
d3d->mask2texture_h = (float)img.height;
if (!allocsprite(d3d, &d3d->mask2texture, img.width, img.height, true, true, false))
goto end;
D3D11_MAPPED_SUBRESOURCE map;
hr = d3d->m_deviceContext->Map(d3d->mask2texture.texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
if (FAILED(hr))
goto end;
for (int i = 0; i < img.height; i++) {
for (int j = 0; j < img.width; j++) {
uae_u32 v;
uae_u32 *sptr = (uae_u32*)((uae_u8*)img.data + i * img.pitch + j * 4);
uae_u32 *ptr = (uae_u32*)((uae_u8*)map.pData + i * map.RowPitch + j * 4);
v = *sptr;
*ptr = v;
}
}
d3d->m_deviceContext->Unmap(d3d->mask2texture.texture, 0);
d3d->mask2rect.left = 0;
d3d->mask2rect.top = 0;
d3d->mask2rect.right = (LONG)d3d->mask2texture_w;
d3d->mask2rect.bottom = (LONG)d3d->mask2texture_h;
d3d->mask2rect.left = findedge(&img, (int)d3d->mask2texture_w, (int)d3d->mask2texture_h, -1, 0);
d3d->mask2rect.right = findedge(&img, (int)d3d->mask2texture_w, (int)d3d->mask2texture_h, 1, 0);
d3d->mask2rect.top = findedge(&img, (int)d3d->mask2texture_w, (int)d3d->mask2texture_h, 0, -1);
d3d->mask2rect.bottom = findedge(&img, (int)d3d->mask2texture_w, (int)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 = (LONG)d3d->mask2texture_w;
d3d->mask2rect.bottom = (LONG)d3d->mask2texture_h;
}
d3d->mask2texture_multx = (float)d3d->m_screenWidth / d3d->mask2texture_w;
d3d->mask2texture_multy = (float)d3d->m_screenHeight / d3d->mask2texture_h;
d3d->mask2texture_offsetw = 0;
if (isfs(d3d) > 0) {
struct MultiDisplay *md = getdisplay(&currprefs, mon->monitor_id);
float deskw = (float)md->rect.right - md->rect.left;
float deskh = (float)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 = (float)d3d->m_screenHeight;
d3d->mask2texture_ww = d3d->mask2texture_w * d3d->mask2texture_multx;
d3d->mask2texture_offsetw = (d3d->m_screenWidth - d3d->mask2texture_ww) / 2;
if (d3d->mask2texture_offsetw > 0) {
allocsprite(d3d, &d3d->blanksprite, (int)(d3d->mask2texture_offsetw + 1), d3d->m_screenHeight, false, false, false);
}
xmult = d3d->mask2texture_multx;
ymult = d3d->mask2texture_multy;
d3d->mask2rect.left = (int)(d3d->mask2rect.left * xmult);
d3d->mask2rect.right = (int)(d3d->mask2rect.right * xmult);
d3d->mask2rect.top = (int)(d3d->mask2rect.top * ymult);
d3d->mask2rect.bottom = (int)(d3d->mask2rect.bottom * ymult);
d3d->mask2texture_wwx = d3d->mask2texture_w * xmult;
if (d3d->mask2texture_wwx > d3d->m_screenWidth)
d3d->mask2texture_wwx = (float)d3d->m_screenWidth;
if (d3d->mask2texture_wwx < d3d->mask2rect.right - d3d->mask2rect.left)
d3d->mask2texture_wwx = (float)d3d->mask2rect.right - d3d->mask2rect.left;
if (d3d->mask2texture_wwx > d3d->mask2texture_ww)
d3d->mask2texture_wwx = d3d->mask2texture_ww;
d3d->mask2texture_minusx = (float)(-((d3d->m_screenWidth - d3d->mask2rect.right) + d3d->mask2rect.left));
if (d3d->mask2texture_offsetw > 0)
d3d->mask2texture_minusx += d3d->mask2texture_offsetw * xmult;
d3d->mask2texture_minusy = (float)(-(d3d->m_screenHeight - (d3d->mask2rect.bottom - d3d->mask2rect.top)));
d3d->mask2texture_hhx = d3d->mask2texture_h * ymult;
write_log(_T("Overlay: '%s' %.0f*%.0f (%d*%d - %d*%d) (%d*%d)\n"),
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);
d3d->mask2texture.enabled = true;
d3d->mask2texture.bilinear = true;
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);
if (allocsprite(d3d, &d3d->mask2textureleds[i], ledimg.width, ledimg.height, true, false, false)) {
D3D11_MAPPED_SUBRESOURCE map;
hr = d3d->m_deviceContext->Map(d3d->mask2textureleds[i].texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
if (SUCCEEDED(hr)) {
for (int j = 0; j < ledimg.height; j++) {
memcpy((uae_u8*)map.pData + j * map.RowPitch, ledimg.data + j * ledimg.pitch, ledimg.width * 4);
}
d3d->m_deviceContext->Unmap(d3d->mask2textureleds[i].texture, 0);
}
d3d->mask2textureleds[i].enabled = true;
d3d->mask2textureleds[i].bilinear = true;
if (ledtypes[i] == LED_POWER) {
if (allocsprite(d3d, &d3d->mask2textureled_power_dim, ledimg.width, ledimg.height, true, false, false)) {
hr = d3d->m_deviceContext->Map(d3d->mask2textureled_power_dim.texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
if (SUCCEEDED(hr)) {
for (int j = 0; j < ledimg.height; j++) {
uae_u8 *pd = (uae_u8*)map.pData + j * map.RowPitch;
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->m_deviceContext->Unmap(d3d->mask2textureled_power_dim.texture, 0);
}
d3d->mask2textureled_power_dim.enabled = true;
d3d->mask2textureled_power_dim.bilinear = true;
}
}
}
} 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);
freesprite(&d3d->mask2texture);
freesprite(&d3d->blanksprite);
return 0;
}
static int createmasktexture(struct d3d11struct *d3d, const TCHAR *filename, struct shaderdata11 *sd)
{
struct zfile *zf;
HRESULT hr;
TCHAR tmp[MAX_DPATH];
int maskwidth, maskheight;
int idx = 0;// sd - &d3d->shaders[0];
D3D11_MAPPED_SUBRESOURCE map;
D3D11_TEXTURE2D_DESC desc;
if (filename[0] == 0)
return 0;
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("Couldn't open mask '%s':%d\n"), filename, idx);
return 0;
}
}
struct uae_image img;
if (!load_png_image(zf, &img)) {
write_log(_T("Temp mask texture '%s' load failed:%d\n"), filename, idx);
goto end;
}
sd->masktexture_w = img.width;
sd->masktexture_h = img.height;
// both must be divisible by mask size
maskwidth = ((d3d->m_screenWidth + sd->masktexture_w - 1) / sd->masktexture_w) * sd->masktexture_w;
maskheight = ((d3d->m_screenHeight + sd->masktexture_h - 1) / sd->masktexture_h) * sd->masktexture_h;
memset(&desc, 0, sizeof desc);
desc.Width = maskwidth;
desc.Height = maskheight;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = d3d->texformat;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
hr = d3d->m_device->CreateTexture2D(&desc, NULL, &sd->masktexture);
if (FAILED(hr)) {
write_log(_T("Mask texture creation failed: %s:%d\n"), hr, idx);
return false;
}
hr = d3d->m_deviceContext->Map(sd->masktexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
if (SUCCEEDED(hr)) {
int x, y, sx, sy;
uae_u32 *sptr, *ptr;
sy = 0;
for (y = 0; y < maskheight; y++) {
sx = 0;
for (x = 0; x < maskwidth; x++) {
uae_u32 v;
sptr = (uae_u32*)((uae_u8*)img.data + sy * img.pitch + sx * 4);
ptr = (uae_u32*)((uae_u8*)map.pData + y * map.RowPitch + x * 4);
v = *sptr;
*ptr = v;
sx++;
if (sx >= sd->masktexture_w)
sx = 0;
}
sy++;
if (sy >= sd->masktexture_h)
sy = 0;
}
d3d->m_deviceContext->Unmap(sd->masktexture, 0);
}
sd->masktexture_w = maskwidth;
sd->masktexture_h = maskheight;
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Texture2D.MipLevels = desc.MipLevels;
srvDesc.Format = d3d->texformat;
hr = d3d->m_device->CreateShaderResourceView(sd->masktexture, &srvDesc, &sd->masktexturerv);
if (FAILED(hr)) {
write_log(_T("CreateShaderResourceView MASK failed: %08x\n"), hr);
goto end;
}
write_log(_T("Mask %d*%d (%d*%d) %d*%d ('%s':%d) texture allocated\n"), sd->masktexture_w, sd->masktexture_h,
img.width, img.height, 0, 0, filename, idx);
free_uae_image(&img);
return 1;
end:
FreeTexture2D(&sd->masktexture, NULL);
free_uae_image(&img);
return 0;
}
#if 0
static void OutputShaderErrorMessage(ID3D10Blob* errorMessage, HWND hwnd, TCHAR* shaderFilename)
{
char *compileErrors;
unsigned long bufferSize;
if (errorMessage) {
// Get a pointer to the error message text buffer.
compileErrors = (char*)(errorMessage->GetBufferPointer());
// Get the length of the message.
bufferSize = errorMessage->GetBufferSize();
TCHAR *s = au(compileErrors);
write_log(_T("D3D11 Shader error: %s"), s);
xfree(s);
// Release the error message.
errorMessage->Release();
} else {
write_log(_T("D3D11 Shader error: %08x"), GetLastError());
}
}
#endif
static bool TextureShaderClass_InitializeShader(struct d3d11struct *d3d)
{
HRESULT result;
D3D11_SAMPLER_DESC samplerDesc;
for (int i = 0; i < 3; i++) {
ID3D11PixelShader **ps = NULL;
const BYTE *Buffer = NULL;
int BufferSize = 0;
char *name;
if (gfx_hdr) {
switch (i)
{
case 0:
name = "PS_PostPlain_HDR";
ps = &d3d->m_pixelShader;
Buffer = PS_PostPlain_HDR;
BufferSize = sizeof(PS_PostPlain_HDR);
break;
case 1:
name = "PS_PostMask_HDR";
ps = &d3d->m_pixelShaderMask;
Buffer = PS_PostMask_HDR;
BufferSize = sizeof(PS_PostMask_HDR);
break;
case 2:
name = "PS_PostAlpha_HDR";
ps = &d3d->m_pixelShaderSL;
Buffer = PS_PostAlpha_HDR;
BufferSize = sizeof(PS_PostAlpha_HDR);
break;
}
} else {
switch (i)
{
case 0:
name = "PS_PostPlain";
ps = &d3d->m_pixelShader;
Buffer = PS_PostPlain;
BufferSize = sizeof(PS_PostPlain);
break;
case 1:
name = "PS_PostMask";
ps = &d3d->m_pixelShaderMask;
Buffer = PS_PostMask;
BufferSize = sizeof(PS_PostMask);
break;
case 2:
name = "PS_PostAlpha";
ps = &d3d->m_pixelShaderSL;
Buffer = PS_PostAlpha;
BufferSize = sizeof(PS_PostAlpha);
break;
}
}
// Create the pixel shader from the buffer.
result = d3d->m_device->CreatePixelShader(Buffer, BufferSize, NULL, ps);
if (FAILED(result))
{
write_log(_T("ID3D11Device CreatePixelShader %08x\n"), result);
return false;
}
#ifndef NDEBUG
static const char psname[] = "shader";
(*ps)->SetPrivateData(WKPDID_D3DDebugObjectName, sizeof(psname) - 1, psname);
#endif
}
D3D11_BUFFER_DESC psBufferDesc;
psBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
psBufferDesc.ByteWidth = sizeof(PSBufferType);
psBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
psBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
psBufferDesc.MiscFlags = 0;
psBufferDesc.StructureByteStride = 0;
result = d3d->m_device->CreateBuffer(&psBufferDesc, NULL, &d3d->m_psBuffer);
if (FAILED(result))
{
write_log(_T("ID3D11Device CreateBuffer(ps) %08x\n"), result);
return false;
}
#ifndef NDEBUG
static const char pname[] = "psbuffer";
d3d->m_psBuffer->SetPrivateData(WKPDID_D3DDebugObjectName, sizeof(pname) - 1, pname);
#endif
if (!createvertexshader(d3d, &d3d->m_vertexShader, &d3d->m_matrixBuffer, &d3d->m_layout))
return false;
// Create a texture sampler state description.
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.MipLODBias = 0.0f;
samplerDesc.MaxAnisotropy = 1;
samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
samplerDesc.BorderColor[0] = 0;
samplerDesc.BorderColor[1] = 0;
samplerDesc.BorderColor[2] = 0;
samplerDesc.BorderColor[3] = 0;
samplerDesc.MinLOD = 0;
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
// Create the texture sampler state.
result = d3d->m_device->CreateSamplerState(&samplerDesc, &d3d->m_sampleState_point_clamp);
if (FAILED(result))
{
write_log(_T("ID3D11Device CreateSamplerState1 %08x\n"), result);
return false;
}
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
result = d3d->m_device->CreateSamplerState(&samplerDesc, &d3d->m_sampleState_linear_clamp);
if (FAILED(result))
{
write_log(_T("ID3D11Device CreateSamplerState2 %08x\n"), result);
return false;
}
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
// Create the texture sampler state.
result = d3d->m_device->CreateSamplerState(&samplerDesc, &d3d->m_sampleState_point_wrap);
if (FAILED(result))
{
write_log(_T("ID3D11Device CreateSamplerState1 %08x\n"), result);
return false;
}
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
result = d3d->m_device->CreateSamplerState(&samplerDesc, &d3d->m_sampleState_linear_wrap);
if (FAILED(result))
{
write_log(_T("ID3D11Device CreateSamplerState2 %08x\n"), result);
return false;
}
return true;
}
static bool initd3d(struct d3d11struct *d3d, int monid)
{
HRESULT result;
ID3D11Texture2D *backBufferPtr;
D3D11_RASTERIZER_DESC rasterDesc;
if (d3d->d3dinit_done)
return true;
write_log(_T("D3D11 initd3d start\n"));
// Get the pointer to the back buffer.
result = d3d->m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&backBufferPtr);
if (FAILED(result))
{
write_log(_T("IDXGISwapChain1 GetBuffer %08x\n"), result);
return false;
}
// Create the render target view with the back buffer pointer.
result = d3d->m_device->CreateRenderTargetView(backBufferPtr, NULL, &d3d->m_renderTargetView);
if (FAILED(result))
{
write_log(_T("ID3D11Device CreateRenderTargetView %08x\n"), result);
backBufferPtr->Release();
return false;
}
// Release pointer to the back buffer as we no longer need it.
backBufferPtr->Release();
backBufferPtr = NULL;
// Setup the raster description which will determine how and what polygons will be drawn.
rasterDesc.AntialiasedLineEnable = false;
rasterDesc.CullMode = D3D11_CULL_NONE;
rasterDesc.DepthBias = 0;
rasterDesc.DepthBiasClamp = 0.0f;
rasterDesc.DepthClipEnable = d3d11_feature_level < D3D10_FEATURE_LEVEL_10_0 ? true : false;
rasterDesc.FillMode = D3D11_FILL_SOLID;
rasterDesc.FrontCounterClockwise = false;
rasterDesc.MultisampleEnable = false;
rasterDesc.ScissorEnable = false;
rasterDesc.SlopeScaledDepthBias = 0.0f;
// Create the rasterizer state from the description we just filled out.
result = d3d->m_device->CreateRasterizerState(&rasterDesc, &d3d->m_rasterState);
if (FAILED(result))
{
write_log(_T("ID3D11Device CreateRasterizerState %08x\n"), result);
return false;
}
// Now set the rasterizer state.
d3d->m_deviceContext->RSSetState(d3d->m_rasterState);
d3d->m_deviceContext->OMSetDepthStencilState(0, 0);
D3D11_BLEND_DESC blendStateDescription;
// Clear the blend state description.
ZeroMemory(&blendStateDescription, sizeof(D3D11_BLEND_DESC));
// Create an alpha enabled blend state description.
blendStateDescription.RenderTarget[0].BlendEnable = TRUE;
//blendStateDescription.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
blendStateDescription.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
blendStateDescription.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
blendStateDescription.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blendStateDescription.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
blendStateDescription.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
blendStateDescription.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blendStateDescription.RenderTarget[0].RenderTargetWriteMask = 0x0f;
// Create the blend state using the description.
result = d3d->m_device->CreateBlendState(&blendStateDescription, &d3d->m_alphaEnableBlendingState);
if (FAILED(result))
{
write_log(_T("ID3D11Device CreateBlendState Alpha %08x\n"), result);
return false;
}
// Modify the description to create an alpha disabled blend state description.
blendStateDescription.RenderTarget[0].BlendEnable = FALSE;
// Create the blend state using the description.
result = d3d->m_device->CreateBlendState(&blendStateDescription, &d3d->m_alphaDisableBlendingState);
if (FAILED(result))
{
write_log(_T("ID3D11Device CreateBlendState NoAlpha %08x\n"), result);
return false;
}
// Setup the viewport for rendering.
d3d->viewport.Width = (float)d3d->m_screenWidth;
d3d->viewport.Height = (float)d3d->m_screenHeight;
d3d->viewport.MinDepth = 0.0f;
d3d->viewport.MaxDepth = 1.0f;
d3d->viewport.TopLeftX = 0.0f;
d3d->viewport.TopLeftY = 0.0f;
// Create the viewport.
d3d->m_deviceContext->RSSetViewports(1, &d3d->viewport);
// Initialize the world matrix to the identity matrix.
xD3DXMatrixIdentity(&d3d->m_worldMatrix);
// Create an orthographic projection matrix for 2D rendering.
xD3DXMatrixOrthoLH(&d3d->m_orthoMatrix, (float)d3d->m_screenWidth, (float)d3d->m_screenHeight, 0.0f, 1.0f);
d3d->m_positionX = 0.0f;
d3d->m_positionY = 0.0f;
d3d->m_positionZ = 1.0f;
d3d->m_rotationX = 0.0f;
d3d->m_rotationY = 0.0f;
d3d->m_rotationZ = 0.0f;
if (!TextureShaderClass_InitializeShader(d3d))
return false;
if (!InitializeBuffers(d3d, &d3d->m_vertexBuffer, &d3d->m_indexBuffer))
return false;
if (!UpdateBuffers(d3d, monid))
return false;
settransform(d3d, NULL);
d3d->d3dinit_done = true;
write_log(_T("D3D11 initd3d end\n"));
return true;
}
static void setswapchainmode(struct d3d11struct *d3d, int fs)
{
struct amigadisplay *ad = &adisplays[d3d->num];
struct apmode *apm = ad->picasso_on ? &currprefs.gfx_apmode[APMODE_RTG] : &currprefs.gfx_apmode[APMODE_NATIVE];
// It is recommended to always use the tearing flag when it is supported.
d3d->swapChainDesc.Flags &= ~DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
if (d3d->m_tearingSupport && (d3d->swapChainDesc.SwapEffect == DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL || d3d->swapChainDesc.SwapEffect == DXGI_SWAP_EFFECT_FLIP_DISCARD)) {
d3d->swapChainDesc.Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
}
if (0 && os_win8 > 1 && fs <= 0) {
d3d->swapChainDesc.Flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
}
d3d->swapChainDesc.Flags &= ~DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
// tearing flag is not fullscreen compatible
if (fs > 0) {
d3d->swapChainDesc.Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
d3d->swapChainDesc.Flags &= ~DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
}
d3d->fsSwapChainDesc.Windowed = TRUE;
}
static const TCHAR *d3dcompiler2 = _T("D3DCompiler_46.dll");
static const TCHAR *d3dcompiler1 = _T("D3DCompiler_47.dll");
static const TCHAR *d3dcompiler = NULL;
int can_D3D11(bool checkdevice)
{
static bool detected;
static int detected_val = 0;
HRESULT hr;
int ret = 0;
if (detected && !checkdevice)
return detected_val;
detected = true;
if (!hd3d11)
hd3d11 = LoadLibrary(_T("D3D11.dll"));
if (!hdxgi)
hdxgi = LoadLibrary(_T("Dxgi.dll"));
if (!dwmapi)
dwmapi = LoadLibrary(_T("Dwmapi.dll"));
if (!hd3dcompiler) {
d3dcompiler = d3dcompiler1;
hd3dcompiler = LoadLibrary(d3dcompiler);
if (!hd3dcompiler) {
d3dcompiler = d3dcompiler2;
hd3dcompiler = LoadLibrary(d3dcompiler);
}
if (!hd3dcompiler) {
d3dcompiler = NULL;
}
}
if (!hd3d11 || !hdxgi) {
write_log(_T("D3D11.dll=%p Dxgi.dll=%p\n"), hd3d11, hdxgi);
return 0;
}
pD3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(GetModuleHandle(_T("D3D11.dll")), "D3D11CreateDevice");
pCreateDXGIFactory1 = (CREATEDXGIFACTORY1)GetProcAddress(GetModuleHandle(_T("Dxgi.dll")), "CreateDXGIFactory1");
if (hd3dcompiler && d3dcompiler) {
HMODULE h = GetModuleHandle(d3dcompiler);
pD3DCompileFromFile = (D3DCOMPILEFROMFILE)GetProcAddress(h, "D3DCompileFromFile");
ppD3DCompile = (D3DCOMPILE)GetProcAddress(h, "D3DCompile");
ppD3DCompile2 = (D3DCOMPILE2)GetProcAddress(h, "D3DCompile2");
pD3DReflect = (D3DREFLECT)GetProcAddress(h, "D3DReflect");
pD3DGetBlobPart = (D3DGETBLOBPART)GetProcAddress(h, "D3DGetBlobPart");
}
if (!pD3D11CreateDevice || !pCreateDXGIFactory1) {
write_log(_T("pD3D11CreateDevice=%p pCreateDXGIFactory1=%p\n"),
pD3D11CreateDevice, pCreateDXGIFactory1);
return 0;
}
if (!pDwmGetCompositionTimingInfo && dwmapi) {
pDwmGetCompositionTimingInfo = (DWMGETCOMPOSITIONTIMINGINFO)GetProcAddress(dwmapi, "DwmGetCompositionTimingInfo");
}
if (ppD3DCompile && pD3DReflect && pD3DGetBlobPart)
ret |= 4;
// Create a DirectX graphics interface factory.
ComPtr<IDXGIFactory4> factory4;
hr = pCreateDXGIFactory1(__uuidof(IDXGIFactory4), (void**)&factory4);
if (SUCCEEDED(hr)) {
ComPtr<IDXGIFactory5> factory5;
BOOL allowTearing = FALSE;
hr = factory4.As(&factory5);
if (SUCCEEDED(hr)) {
hr = factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing));
if (SUCCEEDED(hr) && allowTearing) {
ret |= 2;
}
}
}
if (checkdevice) {
static const D3D_FEATURE_LEVEL levels[] = { D3D_FEATURE_LEVEL_9_1 };
UINT cdflags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
ID3D11Device *m_device;
ID3D11DeviceContext *m_deviceContext;
HRESULT hr = pD3D11CreateDevice(NULL, currprefs.gfx_api_options == 0 ? D3D_DRIVER_TYPE_HARDWARE : D3D_DRIVER_TYPE_WARP,
NULL, cdflags, levels, 1, D3D11_SDK_VERSION, &m_device, NULL, &m_deviceContext);
if (FAILED(hr)) {
write_log(_T("D3D11 check failed. %08x\n"), hr);
return 0;
}
m_deviceContext->Release();
m_device->Release();
}
ret |= 1;
detected_val = ret;
return ret;
}
static bool device_error(struct d3d11struct *d3d)
{
d3d->device_errors++;
if (d3d->device_errors > 2) {
d3d->delayedfs = -1;
return true;
}
return false;
}
static void do_black(struct d3d11struct *d3d)
{
float color[4];
color[0] = 0;
color[1] = 0;
color[2] = 0;
color[3] = 0;
// Bind the render target view and depth stencil buffer to the output render pipeline.
d3d->m_deviceContext->OMSetRenderTargets(1, &d3d->m_renderTargetView, NULL);
// Clear the back buffer.
d3d->m_deviceContext->ClearRenderTargetView(d3d->m_renderTargetView, color);
d3d->m_deviceContext->Flush();
}
static void do_present(struct d3d11struct *d3d)
{
struct amigadisplay *ad = &adisplays[d3d->num];
struct apmode *apm = ad->picasso_on ? &currprefs.gfx_apmode[APMODE_RTG] : &currprefs.gfx_apmode[APMODE_NATIVE];
HRESULT hr;
UINT presentFlags = 0;
int vsync = isvsync();
UINT syncinterval = d3d->vblankintervals;
// only if no vsync or low latency vsync
if (d3d->m_tearingSupport && (d3d->swapChainDesc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) && (!vsync || apm->gfx_vsyncmode)) {
if (apm->gfx_vsyncmode || d3d->num > 0 || currprefs.turbo_emulation || (currprefs.gfx_variable_sync > 0 || (isfs(d3d) <= 0) && currprefs.gfx_variable_sync >= 0)) {
presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
syncinterval = 0;
}
}
if (!vsync) {
if (apm->gfx_backbuffers == 0 || (presentFlags & DXGI_PRESENT_ALLOW_TEARING) || (apm->gfx_vflip == 0 && isfs(d3d) <= 0) || (isfs(d3d) > 0 && apm->gfx_vsyncmode))
syncinterval = 0;
}
d3d->syncinterval = syncinterval;
if (currprefs.turbo_emulation) {
static int skip;
static int toggle;
if (--skip > 0)
return;
skip = 10 + toggle;
toggle = !toggle;
if (os_win8)
presentFlags |= DXGI_PRESENT_DO_NOT_WAIT;
syncinterval = 0;
}
hr = d3d->m_swapChain->Present(syncinterval, presentFlags);
if (currprefs.turbo_emulation && hr == DXGI_ERROR_WAS_STILL_DRAWING)
hr = S_OK;
if (FAILED(hr) && hr != DXGI_STATUS_OCCLUDED) {
if (hr == DXGI_ERROR_DEVICE_REMOVED) {
device_error(d3d);
} else if (hr == E_OUTOFMEMORY) {
d3d->invalidmode = true;
}
write_log(_T("D3D11 Present %08x\n"), hr);
}
slicecnt++;
}
static float xD3D_getrefreshrate(int monid)
{
struct d3d11struct *d3d = &d3d11data[monid];
d3d->lastframe = 0;
if (isfs(d3d) != 0 && d3d->fsSwapChainDesc.RefreshRate.Denominator) {
d3d->vblank = (float)d3d->fsSwapChainDesc.RefreshRate.Numerator / d3d->fsSwapChainDesc.RefreshRate.Denominator;
return d3d->vblank;
}
if (!pDwmGetCompositionTimingInfo)
return 0;
DWM_TIMING_INFO ti;
ti.cbSize = sizeof ti;
HRESULT hr = pDwmGetCompositionTimingInfo(NULL, &ti);
if (FAILED(hr)) {
write_log(_T("DwmGetCompositionTimingInfo1 %08x\n"), hr);
return 0;
}
d3d->vblank = (float)ti.rateRefresh.uiNumerator / ti.rateRefresh.uiDenominator;
return d3d->vblank;
}
static bool xD3D11_initvals(HWND ahwnd, int monid, int w_w, int w_h, int t_w, int t_h, int depth, int *freq, int mmulth, int mmultv, bool doalloc)
{
struct d3d11struct *d3d = &d3d11data[monid];
bool changed = false;
if (d3d->m_screenWidth != w_w || d3d->m_screenHeight != w_h) {
changed = true;
}
d3d->m_screenWidth = w_w;
d3d->m_screenHeight = w_h;
d3d->dmultxh = mmulth;
d3d->dmultxv = mmultv;
if (d3d->m_device) {
target_graphics_buffer_update(monid, false);
}
return changed;
}
static int xxD3D11_init2(HWND ahwnd, int monid, int w_w, int w_h, int t_w, int t_h, int depth, int *freq, int mmulth, int mmultv)
{
struct d3d11struct *d3d = &d3d11data[monid];
struct amigadisplay *ad = &adisplays[monid];
struct apmode *apm = ad->picasso_on ? &currprefs.gfx_apmode[APMODE_RTG] : &currprefs.gfx_apmode[APMODE_NATIVE];
HRESULT result;
int ret = 0;
ComPtr<IDXGIFactory2> factory2;
ComPtr<IDXGIFactory4> factory4;
ComPtr<IDXGIFactory5> factory5;
IDXGIAdapter1 *adapter;
IDXGIOutput *adapterOutput;
DXGI_ADAPTER_DESC1 adesc;
DXGI_OUTPUT_DESC odesc;
unsigned int numModes = 0;
DXGI_MODE_DESC1 *displayModeList;
DXGI_ADAPTER_DESC adapterDesc;
write_log(_T("D3D11 init start. (%d*%d) (%d*%d) RTG=%d Depth=%d.\n"), w_w, w_h, t_w, t_h, ad->picasso_on, depth);
d3d->filterd3didx = ad->gf_index;
d3d->filterd3d = &currprefs.gf[d3d->filterd3didx];
d3d->delayedfs = 0;
d3d->device_errors = 0;
if (depth != 32) {
return 0;
}
if (!can_D3D11(false)) {
return 0;
}
xD3D11_initvals(ahwnd, monid, w_w, w_h, t_w, t_h, depth, freq, mmulth, mmultv, false);
d3d->ahwnd = ahwnd;
d3d->texformat = DXGI_FORMAT_B8G8R8A8_UNORM;
d3d->scrformat = DXGI_FORMAT_B8G8R8A8_UNORM;
HMONITOR winmon;
struct MultiDisplay *md = NULL;
if (isfullscreen() == 0) {
winmon = MonitorFromWindow(ahwnd, MONITOR_DEFAULTTONEAREST);
} else {
md = getdisplay(&currprefs, monid);
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);
}
// Create a DirectX graphics interface factory.
result = pCreateDXGIFactory1(__uuidof(IDXGIFactory4), (void**)&factory4);
if (FAILED(result))
{
write_log(_T("D3D11 CreateDXGIFactory4 %08x\n"), result);
result = pCreateDXGIFactory1(__uuidof(IDXGIFactory2), (void**)&factory2);
if (FAILED(result)) {
write_log(_T("D3D11 CreateDXGIFactory2 %08x\n"), result);
if (!os_win8) {
gui_message(_T("WinUAE Direct3D 11 mode requires Windows 7 Platform Update (KB2670838). Check Windows Update optional updates or download it from: https://www.microsoft.com/en-us/download/details.aspx?id=36805"));
}
return 0;
}
} else {
BOOL allowTearing = FALSE;
result = factory4.As(&factory5);
if (SUCCEEDED(result)) {
factory2 = factory5;
if (!d3d->m_tearingSupport) {
result = factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing));
d3d->m_tearingSupport = SUCCEEDED(result) && allowTearing;
write_log(_T("CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING) = %08x %d\n"), result, allowTearing);
}
} else {
factory2 = factory4;
}
}
// Use the factory to create an adapter for the primary graphics interface (video card).
UINT adapterNum = 0;
bool outputFound = false;
for (;;) {
adapterOutput = NULL;
result = factory2->EnumAdapters1(adapterNum, &adapter);
if (FAILED(result))
{
if (adapterNum > 0)
break;
write_log(_T("IDXGIFactory2 EnumAdapters1 %08x\n"), result);
return 0;
}
result = adapter->GetDesc1(&adesc);
UINT adapterOutNum = 0;
// Enumerate the monitor
for(;;) {
result = adapter->EnumOutputs(adapterOutNum, &adapterOutput);
if (FAILED(result))
break;
result = adapterOutput->GetDesc(&odesc);
if (SUCCEEDED(result)) {
if (odesc.Monitor == winmon || (md && !_tcscmp(odesc.DeviceName, md->adapterid))) {
outputFound = true;
break;
}
}
adapterOutput->Release();
adapterOutput = NULL;
adapterOutNum++;
}
if (outputFound)
break;
adapter->Release();
adapter = NULL;
adapterNum++;
}
if (!outputFound) {
if (adapter)
adapter->Release();
adapter = NULL;
result = factory2->EnumAdapters1(0, &adapter);
if (FAILED(result)) {
write_log(_T("EnumAdapters1 Default %08x\n"), result);
return 0;
}
result = adapter->EnumOutputs(0, &adapterOutput);
if (FAILED(result)) {
adapter->Release();
adapter = NULL;
write_log(_T("EnumOutputs Default %08x\n"), result);
return 0;
}
}
d3d->outputAdapter = adapterOutput;
ComPtr<IDXGIOutput1> adapterOutputx;
ComPtr<IDXGIOutput6> adapterOutput6;
d3d->hdr = false;
result = adapterOutput->QueryInterface(__uuidof(IDXGIOutput6), &adapterOutput6);
if (FAILED(result)) {
write_log(_T("IDXGIOutput6 QueryInterface %08x\n"), result);
ComPtr<IDXGIOutput1> adapterOutput1;
result = adapterOutput->QueryInterface(__uuidof(IDXGIOutput1), &adapterOutput1);
if (FAILED(result)) {
write_log(_T("IDXGIOutput QueryInterface %08x\n"), result);
return 0;
}
adapterOutputx = std::move(adapterOutput1);
} else {
DXGI_OUTPUT_DESC1 desc1;
result = adapterOutput6->GetDesc1(&desc1);
if (SUCCEEDED(result)) {
write_log(_T("Monitor Rotation=%d BPC=%d ColorSpace=%d\n"), desc1.Rotation, desc1.BitsPerColor, desc1.ColorSpace);
write_log(_T("R=%fx%f G=%fx%f B=%fx%f WP=%fx%f\n"),
desc1.RedPrimary[0], desc1.RedPrimary[1],
desc1.GreenPrimary[0], desc1.GreenPrimary[1],
desc1.BluePrimary[0], desc1.BluePrimary[1],
desc1.WhitePoint[0], desc1.WhitePoint[1]);
write_log(_T("MinL=%f MaxL=%f MaxFFL=%f\n"),
desc1.MinLuminance, desc1.MaxLuminance, desc1.MaxFullFrameLuminance);
d3d->hdr = desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
if (currprefs.gfx_api < 3) {
d3d->hdr = false;
}
}
adapterOutputx = adapterOutput6;
}
if (d3d->hdr) {
//d3d->scrformat = DXGI_FORMAT_R10G10B10A2_UNORM;
d3d->scrformat = DXGI_FORMAT_R16G16B16A16_FLOAT;
gfx_hdr = true;
}
// Get the number of modes that fit the display format for the adapter output (monitor).
result = adapterOutputx->GetDisplayModeList1(d3d->scrformat, DXGI_ENUM_MODES_INTERLACED, &numModes, NULL);
if (FAILED(result))
{
write_log(_T("IDXGIOutput1 GetDisplayModeList1 %08x\n"), result);
return 0;
}
// Create a list to hold all the possible display modes for this monitor/video card combination.
displayModeList = new DXGI_MODE_DESC1[numModes];
if (!displayModeList)
{
write_log(_T("IDXGIAdapter1 GetDesc %08x\n"), result);
return 0;
}
// Now fill the display mode list structures.
result = adapterOutputx->GetDisplayModeList1(d3d->scrformat, DXGI_ENUM_MODES_INTERLACED, &numModes, displayModeList);
if (FAILED(result))
{
write_log(_T("IDXGIAdapter1 GetDesc %08x\n"), result);
return 0;
}
ZeroMemory(&d3d->fsSwapChainDesc, sizeof(d3d->fsSwapChainDesc));
int hz = getrefreshrate(monid, w_w, w_h);
// Now go through all the display modes and find the one that matches the screen width and height.
// When a match is found store the numerator and denominator of the refresh rate for that monitor.
d3d->fsSwapChainDesc.RefreshRate.Denominator = 0;
d3d->fsSwapChainDesc.RefreshRate.Numerator = 0;
d3d->fsSwapChainDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE;
for (int i = 0; i < numModes; i++) {
DXGI_MODE_DESC1 *m = &displayModeList[i];
if (m->Format != d3d->scrformat)
continue;
if (apm->gfx_interlaced && m->ScanlineOrdering != DXGI_MODE_SCANLINE_ORDER_UPPER_FIELD_FIRST)
continue;
if (!apm->gfx_interlaced && m->ScanlineOrdering != DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE)
continue;
if (m->Width == w_w && m->Height == w_h) {
d3d->fsSwapChainDesc.ScanlineOrdering = m->ScanlineOrdering;
d3d->fsSwapChainDesc.Scaling = m->Scaling;
if (!hz) {
write_log(_T("D3D11 found matching fullscreen mode. SLO=%d S=%d. Default refresh rate.\n"), m->ScanlineOrdering, m->Scaling);
break;
}
if (isfs(d3d) != 0 && m->RefreshRate.Numerator && m->RefreshRate.Denominator) {
float mhz = (float)m->RefreshRate.Numerator / m->RefreshRate.Denominator;
if ((int)(mhz + 0.5) == hz || (int)(mhz) == hz) {
d3d->fsSwapChainDesc.RefreshRate.Denominator = m->RefreshRate.Denominator;
d3d->fsSwapChainDesc.RefreshRate.Numerator = m->RefreshRate.Numerator;
write_log(_T("D3D11 found matching refresh rate %d/%d=%.2f. SLO=%d\n"), m->RefreshRate.Numerator, m->RefreshRate.Denominator, (float)mhz, m->ScanlineOrdering);
*freq = hz;
break;
}
}
}
}
if (isfs(d3d) > 0 && (hz == 0 || (d3d->fsSwapChainDesc.RefreshRate.Denominator == 0 && d3d->fsSwapChainDesc.RefreshRate.Numerator == 0))) {
// find highest frequency for selected mode
float ffreq = 0;
for (int i = 0; i < numModes; i++) {
DXGI_MODE_DESC1 *m = &displayModeList[i];
if (m->Format != d3d->scrformat)
continue;
if (apm->gfx_interlaced && m->ScanlineOrdering != DXGI_MODE_SCANLINE_ORDER_UPPER_FIELD_FIRST)
continue;
if (!apm->gfx_interlaced && m->ScanlineOrdering != DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE)
continue;
if (m->Width != w_w || m->Height != w_h)
continue;
if (!m->RefreshRate.Numerator || !m->RefreshRate.Denominator)
continue;
float nfreq = (float)m->RefreshRate.Numerator / m->RefreshRate.Denominator;
if (nfreq > ffreq) {
ffreq = nfreq;
d3d->fsSwapChainDesc.RefreshRate.Denominator = m->RefreshRate.Denominator;
d3d->fsSwapChainDesc.RefreshRate.Numerator = m->RefreshRate.Numerator;
if (!currprefs.gfx_variable_sync) {
*freq = (int)nfreq;
}
}
}
write_log(_T("D3D11 Highest freq: %d/%d=%.2f W=%d H=%d\n"),
d3d->fsSwapChainDesc.RefreshRate.Numerator, d3d->fsSwapChainDesc.RefreshRate.Denominator, ffreq, w_w, w_h);
// then re-confirm with FindClosestMatchingMode1()
DXGI_MODE_DESC1 md1 = { 0 }, md2;
md1.Format = d3d->scrformat;
md1.RefreshRate.Numerator = d3d->fsSwapChainDesc.RefreshRate.Numerator;
md1.RefreshRate.Denominator = d3d->fsSwapChainDesc.RefreshRate.Denominator;
md1.Width = w_w;
md1.Height = w_h;
md1.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
md1.ScanlineOrdering = apm->gfx_interlaced ? DXGI_MODE_SCANLINE_ORDER_UPPER_FIELD_FIRST : DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE;
result = adapterOutputx->FindClosestMatchingMode1(&md1, &md2, NULL);
if (FAILED(result)) {
write_log(_T("FindClosestMatchingMode1 %08x\n"), result);
} else {
d3d->fsSwapChainDesc.RefreshRate.Denominator = md2.RefreshRate.Denominator;
d3d->fsSwapChainDesc.RefreshRate.Numerator = md2.RefreshRate.Numerator;
if (!currprefs.gfx_variable_sync) {
*freq = 0;
if (md2.RefreshRate.Denominator && md2.RefreshRate.Numerator)
*freq = md2.RefreshRate.Numerator / md2.RefreshRate.Denominator;
write_log(_T("D3D11 FindClosestMatchingMode1() %d/%d=%.2f SLO=%d W=%d H=%d\n"),
md2.RefreshRate.Numerator, md2.RefreshRate.Denominator,
(float)md2.RefreshRate.Numerator / md2.RefreshRate.Denominator, md1.ScanlineOrdering,
md2.Width, md2.Height);
}
}
}
if (isfs(d3d) <= 0 && !currprefs.gfx_variable_sync) {
*freq = (int)xD3D_getrefreshrate(monid);
}
// Get the adapter (video card) description.
result = adapter->GetDesc(&adapterDesc);
if (FAILED(result)) {
write_log(_T("IDXGIAdapter1 GetDesc %08x\n"), result);
return 0;
}
result = adapterOutput->GetDesc(&odesc);
if (FAILED(result)) {
write_log(_T("IDXGIAdapter1 GetDesc %08x\n"), result);
return 0;
}
write_log(_T("D3D11 Device: %s [%s] (%d,%d,%d,%d)\n"), adapterDesc.Description, odesc.DeviceName,
odesc.DesktopCoordinates.left, odesc.DesktopCoordinates.top,
odesc.DesktopCoordinates.right, odesc.DesktopCoordinates.bottom);
// Release the display mode list.
delete[] displayModeList;
displayModeList = 0;
// Release the adapter.
adapter->Release();
adapter = 0;
UINT cdflags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
#ifndef NDEBUG
cdflags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
static const D3D_FEATURE_LEVEL levels111[] = { D3D_FEATURE_LEVEL_11_1 };
D3D_FEATURE_LEVEL outlevel;
D3D_DRIVER_TYPE dt = currprefs.gfx_api_options == 0 ? D3D_DRIVER_TYPE_HARDWARE : D3D_DRIVER_TYPE_WARP;
result = pD3D11CreateDevice(NULL, dt, NULL, cdflags, levels111, 1, D3D11_SDK_VERSION, &d3d->m_device, &outlevel, &d3d->m_deviceContext);
if (FAILED(result)) {
write_log(_T("D3D11CreateDevice LEVEL_11_1: %08x\n"), result);
if (result == E_INVALIDARG || result == DXGI_ERROR_UNSUPPORTED) {
result = pD3D11CreateDevice(NULL, dt, NULL, cdflags, NULL, 0, D3D11_SDK_VERSION, &d3d->m_device, &outlevel, &d3d->m_deviceContext);
}
if (FAILED(result)) {
write_log(_T("D3D11CreateDevice %08x. Hardware does not support Direct3D11 Level 9.1 or higher.\n"), result);
return 0;
}
}
#ifndef NDEBUG
static const char dname[] = "device";
static const char cname[] = "context";
d3d->m_device->SetPrivateData(WKPDID_D3DDebugObjectName, sizeof(dname) - 1, dname);
d3d->m_deviceContext->SetPrivateData(WKPDID_D3DDebugObjectName, sizeof(cname) - 1, cname);
d3d->m_device->QueryInterface(IID_ID3D11InfoQueue, (void **)&d3d->m_debugInfoQueue);
if (0 && d3d->m_debugInfoQueue)
{
d3d->m_debugInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, TRUE);
d3d->m_debugInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, TRUE);
d3d->m_debugInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, TRUE);
}
d3d->m_device->QueryInterface(IID_ID3D11Debug, (void **)&d3d->m_debug);
#endif
write_log(_T("D3D11CreateDevice succeeded with level %d.%d. %s.\n"), outlevel >> 12, (outlevel >> 8) & 15,
currprefs.gfx_api_options ? _T("Software WARP driver") : _T("Hardware accelerated"));
d3d11_feature_level = outlevel;
UINT flags = 0;
result = d3d->m_device->CheckFormatSupport(d3d->texformat, &flags);
if (FAILED(result) || !(flags & D3D11_FORMAT_SUPPORT_TEXTURE2D)) {
if (depth != 32)
write_log(_T("Direct3D11: 16-bit texture format is not supported %08x\n"), result);
else
write_log(_T("Direct3D11: 32-bit texture format is not supported!? %08x\n"), result);
if (depth == 32)
return 0;
write_log(_T("Direct3D11: Retrying in 32-bit mode\n"), result);
return -1;
}
// Initialize the swap chain description.
ZeroMemory(&d3d->swapChainDesc, sizeof(d3d->swapChainDesc));
// Set the width and height of the back buffer.
d3d->swapChainDesc.Width = w_w;
d3d->swapChainDesc.Height = w_h;
// Set regular 32-bit surface for the back buffer.
d3d->swapChainDesc.Format = d3d->scrformat;
// Turn multisampling off.
d3d->swapChainDesc.SampleDesc.Count = 1;
d3d->swapChainDesc.SampleDesc.Quality = 0;
// Set the usage of the back buffer.
d3d->swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
d3d->swapChainDesc.BufferCount = apm->gfx_backbuffers + 1;
if (d3d->swapChainDesc.BufferCount < 2)
d3d->swapChainDesc.BufferCount = 2;
if (d3d->swapChainDesc.BufferCount > 2 && isfullscreen() <= 0 && !apm->gfx_vsync) {
write_log(_T("Switch from triple buffer to double buffer (%d).\n"), apm->gfx_vflip);
d3d->swapChainDesc.BufferCount = 2;
apm->gfx_vflip = 0;
}
d3d->swapChainDesc.SwapEffect = os_win8 ? (os_win10 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL) : DXGI_SWAP_EFFECT_SEQUENTIAL;
if (apm->gfx_vsyncmode && isfs(d3d) > 0 && !os_win10) {
d3d->swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
}
d3d->vblankintervals = 0;
if (!monid && apm->gfx_backbuffers > 2 && !isvsync())
d3d->vblankintervals = 1;
cannoclear = false;
if (apm->gfx_vsyncmode) {
cannoclear = true;
}
d3d->swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
setswapchainmode(d3d, isfs(d3d));
d3d->swapChainDesc.Scaling = (d3d->swapChainDesc.SwapEffect == DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL || d3d->swapChainDesc.SwapEffect == DXGI_SWAP_EFFECT_FLIP_DISCARD) ? DXGI_SCALING_NONE : DXGI_SCALING_STRETCH;
d3d->blackscreen = false;
if (!monid && isvsync()) {
int vsync = isvsync();
int hzmult = 0;
getvsyncrate(monid, (float)*freq, &hzmult);
if (hzmult < 0 && !currprefs.gfx_variable_sync && apm->gfx_vsyncmode == 0) {
if (!apm->gfx_strobo) {
d3d->vblankintervals = 2;
} else {
d3d->vblankintervals = 1;
d3d->blackscreen = true;
}
}
if (vsync > 0 && !apm->gfx_vsyncmode) {
if (apm->gfx_strobo)
d3d->blackscreen = true;
d3d->vblankintervals = 1;
int hzmult;
getvsyncrate(monid, (float)hz, &hzmult);
if (hzmult < 0) {
d3d->vblankintervals = 1 + (-hzmult) - (d3d->blackscreen ? 1 : 0);
}
}
}
if (d3d->swapChainDesc.SwapEffect == DXGI_SWAP_EFFECT_FLIP_DISCARD && d3d->vblankintervals > 0)
d3d->swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
// Create the swap chain, Direct3D device, and Direct3D device context.
result = factory2->CreateSwapChainForHwnd(d3d->m_device, ahwnd, &d3d->swapChainDesc, isfs(d3d) != 0 ? &d3d->fsSwapChainDesc : NULL, NULL, &d3d->m_swapChain);
if (FAILED(result)) {
write_log(_T("IDXGIFactory2 CreateSwapChainForHwnd %08x\n"), result);
return 0;
}
{
CComPtr<IDXGISwapChain3> m_swapChain3;
if (SUCCEEDED(d3d->m_swapChain->QueryInterface(&m_swapChain3))) {
if (d3d->hdr) {
if (d3d->scrformat == DXGI_FORMAT_R10G10B10A2_UNORM) {
DXGI_COLOR_SPACE_TYPE type = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
UINT cps;
result = m_swapChain3->CheckColorSpaceSupport(type, &cps);
if (SUCCEEDED(result)) {
if (!(cps & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT))
write_log(_T("CheckColorSpaceSupport(DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) not supported!?\n"));
result = m_swapChain3->SetColorSpace1(type);
if (FAILED(result)) {
write_log(_T("SetColorSpace1 failed %08x\n"), result);
}
} else {
write_log(_T("CheckColorSpaceSupport failed %08x\n"), result);
}
} else {
DXGI_COLOR_SPACE_TYPE type = DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;;
UINT cps;
result = m_swapChain3->CheckColorSpaceSupport(type, &cps);
if (SUCCEEDED(result)) {
if (!(cps & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT))
write_log(_T("CheckColorSpaceSupport(DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709) not supported!?\n"));
result = m_swapChain3->SetColorSpace1(type);
if (FAILED(result)) {
write_log(_T("SetColorSpace1 failed %08x\n"), result);
}
} else {
write_log(_T("CheckColorSpaceSupport failed %08x\n"), result);
}
}
}
IDXGIOutput *dxgiOutput = NULL;
result = m_swapChain3->GetContainingOutput(&dxgiOutput);
if (SUCCEEDED(result)) {
IDXGIOutput2 *dxgiOutput2 = NULL;
result = dxgiOutput->QueryInterface(IID_PPV_ARGS(&dxgiOutput2));
if (SUCCEEDED(result)) {
BOOL mpo = dxgiOutput2->SupportsOverlays();
if (mpo) {
write_log(_T("MultiPlane Overlays supported\n"));
}
dxgiOutput2->Release();
}
dxgiOutput->Release();
}
}
}
{
ComPtr<IDXGIDevice1> dxgiDevice;
result = d3d->m_device->QueryInterface(__uuidof(IDXGIDevice1), &dxgiDevice);
if (FAILED(result)) {
write_log(_T("QueryInterface IDXGIDevice1 %08x\n"), result);
} else {
int f = apm->gfx_backbuffers <= 1 ? 1 : 2;
if (d3d->blackscreen)
f++;
result = dxgiDevice->SetMaximumFrameLatency(f);
if (FAILED(result)) {
write_log(_T("IDXGIDevice1 SetMaximumFrameLatency %08x\n"), result);
}
}
}
IDXGIFactory1 *pFactory = NULL;
result = d3d->m_swapChain->GetParent(__uuidof (IDXGIFactory1), (void **)&pFactory);
if (SUCCEEDED(result)) {
result = pFactory->MakeWindowAssociation(ahwnd, DXGI_MWA_NO_WINDOW_CHANGES | DXGI_MWA_NO_ALT_ENTER | DXGI_MWA_NO_PRINT_SCREEN);
if (FAILED(result)) {
write_log(_T("IDXGIFactory2 MakeWindowAssociation %08x\n"), result);
}
pFactory->Release();
}
result = d3d->m_swapChain->GetDesc1(&d3d->swapChainDesc);
if (FAILED(result)) {
write_log(_T("IDXGIFactory2 GetDesc1 %08x\n"), result);
}
d3d->invalidmode = false;
d3d->fsmode = 0;
clearcnt = 0;
write_log(_T("D3D11 Buffers=%d Flags=%08x Format=%08x Scaling=%d SwapEffect=%d VBI=%d\n"),
d3d->swapChainDesc.BufferCount, d3d->swapChainDesc.Flags, d3d->swapChainDesc.Format,
d3d->swapChainDesc.Scaling, d3d->swapChainDesc.SwapEffect, d3d->vblankintervals);
if (isfs(d3d) > 0)
D3D_resize(monid, 1);
D3D_resize(monid, 0);
ret = 1;
write_log(_T("D3D11 init end\n"));
return ret;
}
static void freed3d(struct d3d11struct *d3d)
{
write_log(_T("D3D11 freed3d start\n"));
d3d->d3dinit_done = false;
if (d3d->m_rasterState) {
d3d->m_rasterState->Release();
d3d->m_rasterState = NULL;
}
if (d3d->m_alphaEnableBlendingState) {
d3d->m_alphaEnableBlendingState->Release();
d3d->m_alphaEnableBlendingState = NULL;
}
if (d3d->m_alphaDisableBlendingState) {
d3d->m_alphaDisableBlendingState->Release();
d3d->m_alphaDisableBlendingState = NULL;
}
if (d3d->m_renderTargetView) {
d3d->m_renderTargetView->Release();
d3d->m_renderTargetView = NULL;
}
if (d3d->m_layout) {
d3d->m_layout->Release();
d3d->m_layout = NULL;
}
if (d3d->m_vertexShader) {
d3d->m_vertexShader->Release();
d3d->m_vertexShader = NULL;
}
if (d3d->m_pixelShader) {
d3d->m_pixelShader->Release();
d3d->m_pixelShader = NULL;
}
if (d3d->m_pixelShaderMask) {
d3d->m_pixelShaderMask->Release();
d3d->m_pixelShaderMask = NULL;
}
if (d3d->m_pixelShaderSL) {
d3d->m_pixelShaderSL->Release();
d3d->m_pixelShaderSL = NULL;
}
if (d3d->m_sampleState_point_wrap) {
d3d->m_sampleState_point_wrap->Release();
d3d->m_sampleState_point_wrap = NULL;
}
if (d3d->m_sampleState_linear_wrap) {
d3d->m_sampleState_linear_wrap->Release();
d3d->m_sampleState_linear_wrap = NULL;
}
if (d3d->m_sampleState_point_clamp) {
d3d->m_sampleState_point_clamp->Release();
d3d->m_sampleState_point_clamp = NULL;
}
if (d3d->m_sampleState_linear_clamp) {
d3d->m_sampleState_linear_clamp->Release();
d3d->m_sampleState_linear_clamp = NULL;
}
if (d3d->m_indexBuffer) {
d3d->m_indexBuffer->Release();
d3d->m_indexBuffer = 0;
}
if (d3d->m_vertexBuffer) {
d3d->m_vertexBuffer->Release();
d3d->m_vertexBuffer = 0;
}
if (d3d->m_matrixBuffer) {
d3d->m_matrixBuffer->Release();
d3d->m_matrixBuffer = 0;
}
if (d3d->m_psBuffer) {
d3d->m_psBuffer->Release();
d3d->m_psBuffer = 0;
}
FreeTextures(d3d);
FreeTexture2D(&d3d->sltexture, &d3d->sltexturerv);
FreeShaderTex(&d3d->lpPostTempTexture);
for (int i = 0; i < MAX_SHADERS; i++) {
struct shaderdata11 *s = &d3d->shaders[i];
freeshaderdata(s);
}
if (d3d->filenotificationhandle)
CloseHandle(d3d->filenotificationhandle);
d3d->filenotificationhandle = NULL;
if (d3d->m_deviceContext) {
d3d->m_deviceContext->ClearState();
}
write_log(_T("D3D11 freed3d end\n"));
}
static void xD3D11_free(int monid, bool immediate)
{
struct d3d11struct *d3d = &d3d11data[monid];
write_log(_T("D3D11 free start\n"));
//freethread(d3d);
freed3d(d3d);
if (d3d->m_swapChain) {
// Before shutting down set to windowed mode or when you release the swap chain it will throw an exception.
d3d->m_swapChain->SetFullscreenState(false, NULL);
d3d->m_swapChain->Release();
d3d->m_swapChain = NULL;
}
if (d3d->m_deviceContext) {
d3d->m_deviceContext->ClearState();
d3d->m_deviceContext->Flush();
d3d->m_deviceContext->Release();
d3d->m_deviceContext = NULL;
}
if (d3d->m_device) {
d3d->m_device->Release();
d3d->m_device = NULL;
}
if (d3d->outputAdapter) {
d3d->outputAdapter->Release();
d3d->outputAdapter = NULL;
}
#ifndef NDEBUG
if (d3d->m_debugInfoQueue) {
d3d->m_debugInfoQueue->Release();
d3d->m_debugInfoQueue = NULL;
}
if (d3d->m_debug) {
d3d->m_debug->ReportLiveDeviceObjects(D3D11_RLDO_SUMMARY | D3D11_RLDO_DETAIL);
d3d->m_debug->Release();
d3d->m_debug = NULL;
}
#endif
d3d->device_errors = 0;
changed_prefs.leds_on_screen &= ~STATUSLINE_TARGET;
currprefs.leds_on_screen &= ~STATUSLINE_TARGET;
for (int i = 0; i < LED_MAX; i++) {
leds[i] = 0;
}
write_log(_T("D3D11 free end\n"));
}
static int xxD3D11_init(HWND ahwnd, int monid, int w_w, int w_h, int depth, int *freq, int mmulth, int mmultv)
{
return xxD3D11_init2(ahwnd, monid, w_w, w_h, w_w, w_h, depth, freq, mmulth, mmultv);
}
static const TCHAR *xD3D11_init(HWND ahwnd, int monid, int w_w, int w_h, int depth, int *freq, int mmulth, int mmultv, int *errp)
{
bool reset = false;
if (!can_D3D11(false)) {
*errp = 1;
return _T("D3D11 FAILED TO INIT");
}
struct d3d11struct *d3d = &d3d11data[monid];
struct amigadisplay *ad = &adisplays[monid];
if (!D3D_isenabled(monid)) {
reset = true;
}
if (d3d->filterd3didx != ad->gf_index) {
struct gfx_filterdata *f1 = &currprefs.gf[d3d->filterd3didx];
if (!f1->enable) {
f1 = &currprefs.gf[0];
}
struct gfx_filterdata *f2 = &currprefs.gf[ad->gf_index];
if (!f2->enable) {
f2 = &currprefs.gf[0];
}
if (f1 != f2) {
if (f1->gfx_filter != f2->gfx_filter) {
reset = true;
}
for (int i = 0; i < MAX_FILTERSHADERS * 2 + 1; i++) {
if (_tcsicmp(f1->gfx_filtershader[i], f2->gfx_filtershader[i])) {
reset = true;
}
if (_tcsicmp(f1->gfx_filtermask[i], f2->gfx_filtermask[i])) {
reset = true;
}
}
if (_tcsicmp(f1->gfx_filteroverlay, f2->gfx_filteroverlay)) {
reset = true;
}
if (f1->gfx_filter_scanlines != f2->gfx_filter_scanlines) {
reset = true;
}
if (f1->gfx_filter_scanlineratio != f2->gfx_filter_scanlineratio) {
reset = true;
}
if (f1->gfx_filter_scanlinelevel != f2->gfx_filter_scanlinelevel) {
reset = true;
}
if (f1->gfx_filter_scanlineoffset != f2->gfx_filter_scanlineoffset) {
reset = true;
}
}
}
if (reset) {
xD3D11_free(monid, true);
int v = xxD3D11_init(ahwnd, monid, w_w, w_h, depth, freq, mmulth, mmultv);
if (v > 0) {
return NULL;
}
xD3D11_free(monid, true);
*errp = 1;
if (v <= 0) {
return _T("");
}
return _T("D3D11 INITIALIZATION ERROR");
} else {
struct d3d11struct *d3d = &d3d11data[monid];
if (xD3D11_initvals(ahwnd, monid, w_w, w_h, w_w, w_h, depth, freq, mmulth, mmultv, true)) {
d3d->fsresizedo = true;
} else {
*errp = -1;
}
return NULL;
}
}
static void setpsbuffer(struct d3d11struct *d3d, ID3D11Buffer *psbuffer)
{
HRESULT result;
PSBufferType *dataPtr;
D3D11_MAPPED_SUBRESOURCE mappedResource;
// Lock the constant buffer so it can be written to.
result = d3d->m_deviceContext->Map(psbuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
if (FAILED(result))
{
write_log(_T("ID3D11DeviceContext map(ps) %08x\n"), result);
return;
}
float bri = (currprefs.gfx_luminance) * (1.0f / 2000.0f) + 1.0f;
float con = (currprefs.gfx_contrast + 2000.0f) / 2000.0f;
// Get a pointer to the data in the constant buffer.
dataPtr = (PSBufferType *)mappedResource.pData;
dataPtr->brightness = bri;
dataPtr->contrast = con;
// Unlock the constant buffer.
d3d->m_deviceContext->Unmap(psbuffer, 0);
}
static bool setmatrix(struct d3d11struct *d3d, ID3D11Buffer *matrixbuffer, D3DXMATRIX worldMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix)
{
HRESULT result;
D3DXMATRIX worldMatrix2, viewMatrix2, projectionMatrix2;
MatrixBufferType *dataPtr;
D3D11_MAPPED_SUBRESOURCE mappedResource;
// Transpose the matrices to prepare them for the shader.
xD3DXMatrixTranspose(&worldMatrix2, &worldMatrix);
xD3DXMatrixTranspose(&viewMatrix2, &viewMatrix);
xD3DXMatrixTranspose(&projectionMatrix2, &projectionMatrix);
// Lock the constant buffer so it can be written to.
result = d3d->m_deviceContext->Map(matrixbuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
if (FAILED(result))
{
write_log(_T("ID3D11DeviceContext map(matrix) %08x\n"), result);
return false;
}
// Get a pointer to the data in the constant buffer.
dataPtr = (MatrixBufferType*)mappedResource.pData;
// Copy the matrices into the constant buffer.
dataPtr->world = worldMatrix2;
dataPtr->view = viewMatrix2;
dataPtr->projection = projectionMatrix2;
// Unlock the constant buffer.
d3d->m_deviceContext->Unmap(matrixbuffer, 0);
return true;
}
static void RenderBuffers(struct d3d11struct *d3d, ID3D11Buffer *vertexbuffer, ID3D11Buffer *indexbuffer)
{
unsigned int stride;
unsigned int offset;
// Set vertex buffer stride and offset.
stride = sizeof(VertexType);
offset = 0;
// Set the vertex buffer to active in the input assembler so it can be rendered.
d3d->m_deviceContext->IASetVertexBuffers(0, 1, &vertexbuffer, &stride, &offset);
// Set the index buffer to active in the input assembler so it can be rendered.
d3d->m_deviceContext->IASetIndexBuffer(indexbuffer, d3d->index_buffer_bytes == 4 ? DXGI_FORMAT_R32_UINT : DXGI_FORMAT_R16_UINT, 0);
// Set the type of primitive that should be rendered from this vertex buffer, in this case triangles.
d3d->m_deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
}
static void EndScene(struct d3d11struct *d3d)
{
#if 0
if ((d3d->syncinterval || (d3d->swapChainDesc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD)) && d3d->flipped) {
WaitForSingleObject(flipevent2, 100);
d3d->flipped = false;
}
SetEvent(flipevent);
#endif
do_present(d3d);
}
static void TextureShaderClass_RenderShader(struct d3d11struct *d3d)
{
// Set the vertex input layout.
d3d->m_deviceContext->IASetInputLayout(d3d->m_layout);
// Set the vertex and pixel shaders that will be used to render this triangle.
d3d->m_deviceContext->VSSetShader(d3d->m_vertexShader, NULL, 0);
bool mask = false;
for (int i = 0; i < MAX_SHADERS; i++) {
if (d3d->shaders[i].type == SHADERTYPE_MASK_MIDDLE && d3d->shaders[i].masktexturerv) {
mask = true;
}
}
if (mask) {
d3d->m_deviceContext->PSSetShader(d3d->m_pixelShaderMask, NULL, 0);
} else if (d3d->sltexture) {
d3d->m_deviceContext->PSSetShader(d3d->m_pixelShaderSL, NULL, 0);
} else {
d3d->m_deviceContext->PSSetShader(d3d->m_pixelShader, NULL, 0);
}
// Set the sampler state in the pixel shader.
d3d->m_deviceContext->PSSetSamplers(0, 1, d3d->filterd3d->gfx_filter_bilinear ? &d3d->m_sampleState_linear_clamp : &d3d->m_sampleState_point_clamp);
d3d->m_deviceContext->PSSetSamplers(1, 1, d3d->filterd3d->gfx_filter_bilinear ? &d3d->m_sampleState_linear_wrap : &d3d->m_sampleState_point_wrap);
// Render the triangle.
d3d->m_deviceContext->DrawIndexed(INDEXCOUNT, 0, 0);
}
static void RenderSprite(struct d3d11struct *d3d, struct d3d11sprite *spr, int monid)
{
D3DXMATRIX scaling, rotation, translation, worldMatrix;
float left, top;
float w, h;
float rot = 0;
if (!spr->enabled)
return;
left = spr->x;
top = -spr->y;
if (spr->outwidth) {
w = spr->outwidth;
} else {
w = (float)spr->width;
}
if (spr->outheight) {
h = spr->outheight;
} else {
h = (float)spr->height;
}
if (spr->rotation) {
rot = get_rotation(d3d, monid);
}
xD3DXMatrixScaling(&scaling, w, h, 1.0f);
xD3DXMatrixRotationZ(&rotation, rot);
left += (int)(w / 2 + 0.5f) - d3d->m_screenWidth / 2;
top += (int)(-h / 2 - 0.5f) + d3d->m_screenHeight / 2;
xD3DXMatrixTranslation(&translation, left, top, 0.0f);
xD3DXMatrixMultiply(&worldMatrix, &scaling, &rotation);
xD3DXMatrixMultiply(&worldMatrix, &worldMatrix, &translation);
UpdateVertexArray(d3d, spr->vertexbuffer, -0.5f, 0.5f, 0.5f, -0.5f, 0, 0, 0, 0);
RenderBuffers(d3d, spr->vertexbuffer, spr->indexbuffer);
if (!setmatrix(d3d, spr->matrixbuffer, worldMatrix, d3d->m_viewMatrix, d3d->m_orthoMatrix))
return;
if (spr->alpha)
TurnOnAlphaBlending(d3d);
// Now set the constant buffer in the vertex shader with the updated values.
d3d->m_deviceContext->VSSetConstantBuffers(0, 1, &spr->matrixbuffer);
d3d->m_deviceContext->PSSetShaderResources(0, 1, &spr->texturerv);
// Set the vertex input layout.
d3d->m_deviceContext->IASetInputLayout(spr->layout);
// Set the vertex and pixel shaders that will be used to render this triangle.
d3d->m_deviceContext->VSSetShader(spr->vertexshader, NULL, 0);
d3d->m_deviceContext->PSSetShader(spr->pixelshader, NULL, 0);
// Set the sampler state in the pixel shader.
d3d->m_deviceContext->PSSetSamplers(0, 1, spr->bilinear ? &d3d->m_sampleState_linear_clamp : &d3d->m_sampleState_point_clamp);
// Render the triangle.
d3d->m_deviceContext->DrawIndexed(INDEXCOUNT, 0, 0);
if (spr->alpha)
TurnOffAlphaBlending(d3d);
}
static void setspritescaling(struct d3d11sprite *spr, float w, float h)
{
spr->outwidth = w * spr->width;
spr->outheight = h * spr->height;
}
static void renderoverlay(struct d3d11struct *d3d, int monid)
{
if (!d3d->mask2texture.enabled)
return;
struct d3d11sprite *spr = &d3d->mask2texture;
float srcw = d3d->mask2texture_w;
float srch = d3d->mask2texture_h;
float aspectsrc = srcw / srch;
float aspectdst = (float)d3d->m_screenWidth / d3d->m_screenHeight;
setspritescaling(spr, d3d->mask2texture_multx, d3d->mask2texture_multy);
#if 0
v.x = 0;
if (filterd3d->gfx_filteroverlay_pos.x == -1)
v.x = (d3d->m_screenWidth - (d3d->mask2texture_w * w)) / 2;
else if (filterd3d->gfx_filteroverlay_pos.x > -24000)
v.x = filterd3d->gfx_filteroverlay_pos.x;
else
v.x = (d3d->m_screenWidth - (d3d->mask2texture_w * w)) / 2 + (-filterd3d->gfx_filteroverlay_pos.x - 30100) * d3d->m_screenHeight / 100.0;
v.y = 0;
if (filterd3d->gfx_filteroverlay_pos.y == -1)
v.y = (d3d->m_screenWidth - (d3d->mask2texture_h * h)) / 2;
else if (filterd3d->gfx_filteroverlay_pos.y > -24000)
v.y = filterd3d->gfx_filteroverlay_pos.y;
else
v.y = (d3d->m_screenWidth - (d3d->mask2texture_h * h)) / 2 + (-filterd3d->gfx_filteroverlay_pos.y - 30100) * d3d->m_screenHeight / 100.0;
#endif
setsprite(d3d, spr, d3d->mask2texture_offsetw, 0);
RenderSprite(d3d, spr, monid);
for (int i = 0; overlayleds[i]; i++) {
bool led = leds[ledtypes[i]] != 0;
if (led || (ledtypes[i] == LED_POWER && currprefs.power_led_dim)) {
struct d3d11sprite *sprled = &d3d->mask2textureleds[i];
if (!led && ledtypes[i] == LED_POWER && currprefs.power_led_dim)
sprled = &d3d->mask2textureled_power_dim;
if (sprled) {
setspritescaling(sprled, d3d->mask2texture_multx, d3d->mask2texture_multy);
setsprite(d3d, sprled,
d3d->mask2texture_offsetw + d3d->mask2textureledoffsets[i * 2 + 0] * d3d->mask2texture_multx,
d3d->mask2textureledoffsets[i * 2 + 1] * d3d->mask2texture_multy);
RenderSprite(d3d, sprled, monid);
}
}
}
if (d3d->mask2texture_offsetw > 0) {
struct d3d11sprite *bspr = &d3d->blanksprite;
setsprite(d3d, bspr, 0, 0);
RenderSprite(d3d, bspr, monid);
setsprite(d3d, bspr, d3d->mask2texture_offsetw + d3d->mask2texture_ww, 0);
RenderSprite(d3d, bspr, monid);
}
}
static void xD3D11_led(int led, int on, int brightness)
{
struct d3d11struct *d3d = &d3d11data[0];
leds[led] = on;
}
static int xD3D11_debug(int monid, int mode)
{
struct d3d11struct *d3d = &d3d11data[monid];
int old = debugcolors ? 1 : 0;
debugcolors = (mode & 1) != 0;
noclear = debugcolors ? false : true;
clearcnt = 0;
return old;
}
static void clearrt(struct d3d11struct *d3d)
{
// Setup the color to clear the buffer to.
float color[4];
color[0] = 0;
color[1] = 0;
color[2] = 0;
color[3] = 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] = 0.3;
color[v] = 0.3;
}
// Clear the back buffer.
d3d->m_deviceContext->ClearRenderTargetView(d3d->m_renderTargetView, color);
}
static bool renderframe(struct d3d11struct *d3d)
{
ID3D11ShaderResourceView *empty = NULL;
struct shadertex st;
st.tex = d3d->texture2d;
st.rv = d3d->texture2drv;
st.rt = NULL;
TurnOffAlphaBlending(d3d);
d3d->m_deviceContext->PSSetShaderResources(0, 1, &empty);
for (int i = 0; i < MAX_SHADERS; i++) {
struct shaderdata11 *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);
st.vp = &s->viewport;
if (!processshader(d3d, &st, s, true))
return false;
}
}
d3d->m_matProj = d3d->m_matProj_out;
d3d->m_matView = d3d->m_matView_out;
d3d->m_matWorld = d3d->m_matWorld_out;
d3d->m_deviceContext->RSSetViewports(1, &d3d->viewport);
// Set shader texture resource in the pixel shader.
d3d->m_deviceContext->PSSetShaderResources(0, 1, &st.rv);
bool mask = false;
int after = -1;
for (int i = 0; i < MAX_SHADERS; i++) {
struct shaderdata11 *s = &d3d->shaders[i];
if (s->type == SHADERTYPE_MASK_MIDDLE && s->masktexturerv) {
d3d->m_deviceContext->PSSetShaderResources(1, 1, &s->masktexturerv);
mask = true;
}
if (s->type == SHADERTYPE_AFTER)
after = i;
}
if (!mask && d3d->sltexturerv) {
d3d->m_deviceContext->PSSetShaderResources(1, 1, &d3d->sltexturerv);
}
// Set the shader parameters that it will use for rendering.
if (!setmatrix(d3d, d3d->m_matrixBuffer, d3d->m_worldMatrix, d3d->m_viewMatrix, d3d->m_orthoMatrix))
return false;
// Put the bitmap vertex and index buffers on the graphics pipeline to prepare them for drawing.
RenderBuffers(d3d, d3d->m_vertexBuffer, d3d->m_indexBuffer);
// Now set the constant buffer in the vertex shader with the updated values.
d3d->m_deviceContext->VSSetConstantBuffers(0, 1, &d3d->m_matrixBuffer);
setpsbuffer(d3d, d3d->m_psBuffer);
d3d->m_deviceContext->PSSetConstantBuffers(0, 1, &d3d->m_psBuffer);
// Bind the render target view and depth stencil buffer to the output render pipeline.
if (after >= 0) {
d3d->m_deviceContext->OMSetRenderTargets(1, &d3d->lpPostTempTexture.rt, NULL);
} else {
d3d->m_deviceContext->OMSetRenderTargets(1, &d3d->m_renderTargetView, NULL);
clearrt(d3d);
}
// Now render the prepared buffers with the shader.
TextureShaderClass_RenderShader(d3d);
if (after >= 0) {
d3d->m_deviceContext->OMSetRenderTargets(1, &d3d->m_renderTargetView, NULL);
clearrt(d3d);
}
if (after >= 0) {
memcpy(&st, &d3d->lpPostTempTexture, sizeof(struct shadertex));
for (int i = 0; i < MAX_SHADERS; i++) {
struct shaderdata11 *s = &d3d->shaders[i];
if (s->type == SHADERTYPE_AFTER) {
settransform2(d3d, s);
if (i == after)
st.vp = &d3d->viewport;
else
st.vp = &s->viewport;
if (!processshader(d3d, &st, s, i != after))
return false;
}
}
}
return true;
}
static bool TextureShaderClass_Render(struct d3d11struct *d3d, int monid)
{
renderframe(d3d);
RenderSprite(d3d, &d3d->hwsprite, monid);
renderoverlay(d3d, monid);
RenderSprite(d3d, &d3d->osd, monid);
struct d3doverlay *ov = d3d->extoverlays;
while (ov) {
RenderSprite(d3d, &ov->s, monid);
ov = ov->next;
}
return true;
}
static void CameraClass_Render(struct d3d11struct *d3d)
{
D3DXVECTOR3 up, position, lookAt;
float yaw, pitch, roll;
D3DXMATRIX rotationMatrix;
// Setup the vector that points upwards.
up.x = 0.0f;
up.y = 1.0f;
up.z = 0.0f;
// Setup the position of the camera in the world.
position.x = d3d->m_positionX;
position.y = d3d->m_positionY;
position.z = d3d->m_positionZ;
// Setup where the camera is looking by default.
lookAt.x = 0.0f;
lookAt.y = 0.0f;
lookAt.z = 1.0f;
// Set the yaw (Y axis), pitch (X axis), and roll (Z axis) rotations in radians.
pitch = d3d->m_rotationX * 0.0174532925f;
yaw = d3d->m_rotationY * 0.0174532925f;
roll = d3d->m_rotationZ * 0.0174532925f;
// Create the rotation matrix from the yaw, pitch, and roll values.
xD3DXMatrixRotationYawPitchRoll(&rotationMatrix, yaw, pitch, roll);
// Transform the lookAt and up vector by the rotation matrix so the view is correctly rotated at the origin.
xD3DXVec3TransformCoord(&lookAt, &lookAt, &rotationMatrix);
xD3DXVec3TransformCoord(&up, &up, &rotationMatrix);
// Translate the rotated camera position to the location of the viewer.
lookAt = position + lookAt;
// Finally create the view matrix from the three updated vectors.
xD3DXMatrixLookAtLH(&d3d->m_viewMatrix, &position, &lookAt, &up);
}
static bool GraphicsClass_Render(struct d3d11struct *d3d, bool normalrender, int monid)
{
bool result;
setupscenecoords(d3d, normalrender, monid);
// Generate the view matrix based on the camera's position.
CameraClass_Render(d3d);
// Render the bitmap with the texture shader.
result = TextureShaderClass_Render(d3d, monid);
if (!result)
return false;
return true;
}
static struct shaderdata11 *allocshaderslot(struct d3d11struct *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 bool restore(struct d3d11struct *d3d)
{
for (int i = 0; i < MAX_FILTERSHADERS; i++) {
if (d3d->filterd3d->gfx_filtershader[i][0]) {
struct shaderdata11 *s = allocshaderslot(d3d, SHADERTYPE_BEFORE);
if (!psEffect_LoadEffect(d3d, d3d->filterd3d->gfx_filtershader[i], s, i)) {
freeshaderdata(s);
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 shaderdata11 *s = allocshaderslot(d3d, SHADERTYPE_MASK_BEFORE);
if (!createmasktexture(d3d, d3d->filterd3d->gfx_filtermask[i], s)) {
freeshaderdata(s);
}
}
}
if (d3d->filterd3d->gfx_filtershader[2 * MAX_FILTERSHADERS][0]) {
struct shaderdata11 *s = allocshaderslot(d3d, SHADERTYPE_MIDDLE);
if (!psEffect_LoadEffect(d3d, d3d->filterd3d->gfx_filtershader[2 * MAX_FILTERSHADERS], s, 2 * MAX_FILTERSHADERS)) {
freeshaderdata(s);
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 shaderdata11 *s = allocshaderslot(d3d, SHADERTYPE_MASK_MIDDLE);
if (!createmasktexture(d3d, d3d->filterd3d->gfx_filtermask[2 * MAX_FILTERSHADERS], s)) {
freeshaderdata(s);
}
}
for (int i = 0; i < MAX_FILTERSHADERS; i++) {
if (d3d->filterd3d->gfx_filtershader[i + MAX_FILTERSHADERS][0]) {
struct shaderdata11 *s = allocshaderslot(d3d, SHADERTYPE_AFTER);
if (!psEffect_LoadEffect(d3d, d3d->filterd3d->gfx_filtershader[i + MAX_FILTERSHADERS], s, i + MAX_FILTERSHADERS)) {
freeshaderdata(s);
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 shaderdata11 *s = allocshaderslot(d3d, SHADERTYPE_MASK_AFTER);
if (!createmasktexture(d3d, d3d->filterd3d->gfx_filtermask[i + MAX_FILTERSHADERS], s)) {
freeshaderdata(s);
}
}
}
createscanlines(d3d, 1);
createmask2texture(d3d, d3d->filterd3d->gfx_filteroverlay);
int w = d3d->m_bitmapWidth;
int h = d3d->m_bitmapHeight;
if (!createextratextures(d3d, d3d->m_bitmapWidthX, d3d->m_bitmapHeightX, d3d->m_screenWidth, d3d->m_screenHeight))
return false;
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->m_screenWidth;
h2 = d3d->m_screenHeight;
}
if (type == SHADERTYPE_BEFORE || type == SHADERTYPE_AFTER || type == SHADERTYPE_MIDDLE) {
D3D11_TEXTURE3D_DESC desc;
D3D11_MAPPED_SUBRESOURCE map;
HRESULT hr;
memset(&desc, 0, sizeof(desc));
desc.Width = 256;
desc.Height = 16;
desc.Depth = 256;
desc.MipLevels = 1;
desc.Format = d3d->texformat;
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
hr = d3d->m_device->CreateTexture3D(&desc, NULL, &d3d->shaders[i].lpHq2xLookupTexture);
if (FAILED(hr)) {
write_log(_T("D3D11 Failed to create volume texture: %08x:%d\n"), hr, i);
return false;
}
hr = d3d->m_deviceContext->Map(d3d->shaders[i].lpHq2xLookupTexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
if (FAILED(hr)) {
write_log(_T("D3D11 Failed to lock box of volume texture: %08x:%d\n"), hr, i);
return false;
}
write_log(_T("HQ2X texture (%dx%d) (%dx%d):%d\n"), w2, h2, w, h, i);
BuildHq2xLookupTexture(w2, h2, w, h, (unsigned char*)map.pData);
d3d->m_deviceContext->Unmap(d3d->shaders[i].lpHq2xLookupTexture, 0);
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
memset(&srvDesc, 0, sizeof srvDesc);
ID3D11ShaderResourceView *rv = NULL;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Texture2D.MipLevels = 1;
srvDesc.Format = d3d->texformat;
hr = d3d->m_device->CreateShaderResourceView(d3d->shaders[i].lpHq2xLookupTexture, &srvDesc, &d3d->shaders[i].lpHq2xLookupTexturerv);
if (FAILED(hr)) {
write_log(_T("D3D11 Failed to create volume texture resource view: %08x:%d\n"), hr, i);
return false;
}
}
}
write_log(_T("D3D11 Shader and extra textures restored\n"));
return true;
}
static void resizemode(struct d3d11struct *d3d, int monid);
static bool xD3D11_renderframe(int monid, int mode, bool immediate)
{
struct amigadisplay *ad = &adisplays[monid];
struct apmode *apm = ad->picasso_on ? &currprefs.gfx_apmode[APMODE_RTG] : &currprefs.gfx_apmode[APMODE_NATIVE];
struct d3d11struct *d3d = &d3d11data[monid];
d3d->frames_since_init++;
if (mode > 0 && (mode & 2))
slicecnt = 0;
else if (mode < 0)
slicecnt = slicecnt == 2 ? 0 : slicecnt;
if (!d3d->m_swapChain)
return false;
if (d3d->fsmodechange)
D3D_resize(monid, 0);
if (d3d->invalidmode)
return false;
if (d3d->delayedrestore) {
d3d->delayedrestore = false;
restore(d3d);
}
if (d3d->delayedfs || !d3d->texture2d || !d3d->d3dinit_done)
return false;
GraphicsClass_Render(d3d, mode < 0 || (mode & 1), monid);
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) {
write_log(_T("D3D11 shader file modification notification.\n"));
D3D_resize(monid, 0);
}
}
if (apm->gfx_vsyncmode)
d3d->m_deviceContext->Flush();
return true;
}
static void xD3D11_showframe_special(int monid, int mode)
{
struct d3d11struct *d3d = &d3d11data[monid];
if (d3d->invalidmode || d3d->delayedfs || !d3d->texture2d || !d3d->d3dinit_done)
return;
if (!d3d->m_swapChain)
return;
if (mode == 1)
do_present(d3d);
if (mode == 2)
do_black(d3d);
}
static void xD3D11_showframe(int monid)
{
struct d3d11struct *d3d = &d3d11data[monid];
if (d3d->invalidmode || d3d->delayedfs || !d3d->texture2d || !d3d->d3dinit_done)
return;
if (!d3d->m_swapChain)
return;
// Present the rendered scene to the screen.
EndScene(d3d);
}
static void xD3D11_clear(int monid)
{
struct d3d11struct *d3d = &d3d11data[monid];
if (d3d->invalidmode)
return;
if (!d3d->m_swapChain)
return;
// Setup the color to clear the buffer to.
float color[4];
color[0] = 0;
color[1] = 0;
color[2] = 0;
color[3] = 0;
// Bind the render target view and depth stencil buffer to the output render pipeline.
d3d->m_deviceContext->OMSetRenderTargets(1, &d3d->m_renderTargetView, NULL);
// Clear the back buffer.
d3d->m_deviceContext->ClearRenderTargetView(d3d->m_renderTargetView, color);
d3d->m_deviceContext->Flush();
clearcnt = 0;
}
static bool xD3D11_quit(struct d3d11struct *d3d)
{
if (quit_program != -UAE_QUIT && quit_program != UAE_QUIT)
return false;
if (d3d->m_swapChain && (!d3d->invalidmode || d3d->fsmode > 0)) {
d3d->m_swapChain->SetFullscreenState(FALSE, NULL);
FreeTextures(d3d);
}
d3d->fsmode = 0;
d3d->invalidmode = true;
d3d->fsmodechange = 0;
return true;
}
static void xD3D11_refresh(int monid)
{
struct d3d11struct *d3d = &d3d11data[monid];
if (!d3d->m_swapChain)
return;
createscanlines(d3d, 0);
for (int i = 0; i < 3; i++) {
if (xD3D11_renderframe(monid, true, true)) {
xD3D11_showframe(monid);
}
}
clearcnt = 0;
}
static bool D3D11_resize_do(struct d3d11struct *d3d, int monid)
{
HRESULT hr;
if (!d3d->fsresizedo)
return false;
if (!d3d->m_swapChain)
return false;
d3d->fsresizedo = false;
write_log(_T("D3D11 resize do %d %d\n"), d3d->fsmodechange, d3d->fsmode);
if (d3d->fsmodechange && d3d->fsmode > 0) {
write_log(_T("D3D11_resize -> fullscreen\n"));
ShowWindow(d3d->ahwnd, SW_SHOWNORMAL);
hr = d3d->m_swapChain->SetFullscreenState(TRUE, d3d->outputAdapter);
if (FAILED(hr)) {
write_log(_T("SetFullscreenState(TRUE) failed %08X\n"), hr);
toggle_fullscreen(d3d->num, 10);
} else {
d3d->fsmode = 0;
}
d3d->fsmodechange = 0;
d3d->invalidmode = false;
} else if (d3d->fsmodechange && d3d->fsmode < 0) {
write_log(_T("D3D11_resize -> window\n"));
hr = d3d->m_swapChain->SetFullscreenState(FALSE, NULL);
if (FAILED(hr))
write_log(_T("SetFullscreenState(FALSE) failed %08X\n"), hr);
ShowWindow(d3d->ahwnd, SW_MINIMIZE);
d3d->fsmode = 0;
d3d->invalidmode = true;
d3d->fsmodechange = 0;
} else {
d3d->fsmode = 0;
d3d->invalidmode = false;
d3d->fsmodechange = 0;
write_log(_T("D3D11_resize -> none\n"));
}
resizemode(d3d, monid);
write_log(_T("D3D11 resize exit\n"));
return true;
}
static bool recheck(struct d3d11struct *d3d, int monid)
{
bool r = false;
if (xD3D11_quit(d3d))
return r;
r = D3D11_resize_do(d3d, monid);
if (d3d->resizeretry) {
resizemode(d3d, monid);
return r;
}
if (!d3d->delayedfs)
return r;
xD3D11_free(d3d->num, true);
d3d->delayedfs = 0;
ShowWindow(d3d->ahwnd, SW_SHOWNORMAL);
int freq = 0;
if (!xxD3D11_init2(d3d->ahwnd, d3d->num, d3d->m_screenWidth, d3d->m_screenHeight, d3d->m_bitmapWidth2, d3d->m_bitmapHeight2, 32, &freq, d3d->dmultxh, d3d->dmultxv))
d3d->invalidmode = true;
return false;
}
static bool xD3D11_alloctexture(int monid, int w, int h)
{
struct d3d11struct *d3d = &d3d11data[monid];
bool v;
if (w == 0 || h == 0) {
return false;
}
if (w < 0 || h < 0) {
if (d3d->m_bitmapWidth == -w && d3d->m_bitmapHeight == -h && d3d->texture2d) {
return true;
}
return false;
}
recheck(d3d, monid);
if (d3d->invalidmode)
return false;
d3d->m_bitmapWidth = w;
d3d->m_bitmapHeight = h;
d3d->m_bitmapWidth2 = d3d->m_bitmapWidth;
d3d->m_bitmapHeight2 = d3d->m_bitmapHeight;
d3d->dmult = S2X_getmult(monid);
d3d->m_bitmapWidthX = d3d->m_bitmapWidth * d3d->dmultxh;
d3d->m_bitmapHeightX = d3d->m_bitmapHeight * d3d->dmultxv;
v = CreateTexture(d3d);
if (!v)
return false;
if (d3d->reloadshaders) {
d3d->reloadshaders = false;
restore(d3d);
} else {
d3d->delayedrestore = true;
}
setupscenecoords(d3d, true, monid);
changed_prefs.leds_on_screen |= STATUSLINE_TARGET;
currprefs.leds_on_screen |= STATUSLINE_TARGET;
return true;
}
static uae_u8 *xD3D11_locktexture(int monid, int *pitch, int *width, int *height, int fullupdate)
{
struct d3d11struct *d3d = &d3d11data[monid];
// texture allocation must not cause side-effects
if (d3d->invalidmode || !d3d->texture2d)
return NULL;
D3D11_MAPPED_SUBRESOURCE map;
HRESULT hr = d3d->m_deviceContext->Map(d3d->texture2dstaging, 0, D3D11_MAP_WRITE, 0, &map);
if (FAILED(hr)) {
write_log(_T("D3D11 Map() %08x\n"), hr);
return NULL;
}
*pitch = map.RowPitch;
if (height)
*height = d3d->m_bitmapHeight;
if (width)
*width = d3d->m_bitmapWidth;
d3d->texturelocked++;
return (uae_u8*)map.pData;
}
static void xD3D11_unlocktexture(int monid, int y_start, int y_end)
{
struct AmigaMonitor *mon = &AMonitors[monid];
struct d3d11struct *d3d = &d3d11data[monid];
if (!d3d->texturelocked || d3d->invalidmode)
return;
d3d->texturelocked--;
d3d->m_deviceContext->Unmap(d3d->texture2dstaging, 0);
if (y_start < -1 || y_end < -1) {
return;
}
bool rtg = WIN32GFX_IsPicassoScreen(mon);
if (((currprefs.leds_on_screen & STATUSLINE_CHIPSET) && !rtg) || ((currprefs.leds_on_screen & STATUSLINE_RTG) && rtg)) {
d3d->osd.enabled = true;
updateleds(d3d);
} else {
d3d->osd.enabled = false;
}
if (y_start < 0) {
d3d->m_deviceContext->CopyResource(d3d->texture2d, d3d->texture2dstaging);
} else {
D3D11_BOX box = { 0 };
box.right = d3d->m_bitmapWidth;
box.top = y_start;
box.bottom = y_end;
box.back = 1;
d3d->m_deviceContext->CopySubresourceRegion(d3d->texture2d, 0, 0, y_start, 0, d3d->texture2dstaging, 0, &box);
}
}
static void xD3D11_flushtexture(int monid, int miny, int maxy)
{
struct d3d11struct *d3d = &d3d11data[monid];
}
static void xD3D11_restore(int monid, bool checkonly)
{
struct d3d11struct *d3d = &d3d11data[monid];
recheck(d3d, monid);
}
static void xD3D11_vblank_reset(double freq)
{
}
static int xD3D11_canshaders(void)
{
return (can_D3D11(false) & 4) != 0;
}
static int xD3D11_goodenough(void)
{
return 1;
}
static void xD3D11_change(int monid, int temp)
{
struct d3d11struct *d3d = &d3d11data[monid];
clearcnt = 0;
}
static void resizemode(struct d3d11struct *d3d, int monid)
{
d3d->resizeretry = false;
if (!d3d->invalidmode) {
write_log(_T("D3D11 resizemode start\n"));
freed3d(d3d);
int fs = isfs(d3d);
setswapchainmode(d3d, fs);
write_log(_T("D3D11 resizemode %dx%d, %dx%d %d %08x FS=%d\n"), d3d->m_screenWidth, d3d->m_screenHeight, d3d->m_bitmapWidth, d3d->m_bitmapHeight,
d3d->swapChainDesc.BufferCount, d3d->swapChainDesc.Flags, fs);
HRESULT hr = d3d->m_swapChain->ResizeBuffers(d3d->swapChainDesc.BufferCount, d3d->m_screenWidth, d3d->m_screenHeight, d3d->scrformat, d3d->swapChainDesc.Flags);
if (FAILED(hr)) {
write_log(_T("ResizeBuffers %08x\n"), hr);
if (!device_error(d3d)) {
d3d->resizeretry = true;
}
}
if (!d3d->invalidmode) {
if (!initd3d(d3d, monid)) {
xD3D11_free(d3d->num, true);
gui_message(_T("D3D11 Resize failed."));
d3d->invalidmode = true;
} else {
xD3D11_alloctexture(d3d->num, d3d->m_bitmapWidth, d3d->m_bitmapHeight);
}
}
write_log(_T("D3D11 resizemode end\n"));
}
}
static void xD3D11_resize(int monid, int activate)
{
static int recursive;
struct d3d11struct *d3d = &d3d11data[monid];
write_log(_T("D3D11_resize %d %d %d (%d)\n"), activate, d3d->fsmodechange, d3d->fsmode, d3d->guimode);
if (d3d->delayedfs)
return;
if (d3d->guimode && isfullscreen() > 0)
return;
if (quit_program == -UAE_QUIT || quit_program == UAE_QUIT)
return;
if (activate) {
d3d->fsmode = activate;
d3d->fsmodechange = true;
ShowWindow(d3d->ahwnd, d3d->fsmode > 0 ? SW_SHOWNORMAL : SW_MINIMIZE);
write_log(_T("D3D11 resize activate %d\n"), activate);
}
d3d->fsresizedo = true;
}
static void xD3D11_guimode(int monid, int guion)
{
struct d3d11struct *d3d = &d3d11data[monid];
d3d->reloadshaders = true;
if (isfullscreen() <= 0)
return;
write_log(_T("fs guimode %d\n"), guion);
d3d->guimode = guion;
if (guion > 0) {
xD3D11_free(d3d->num, true);
ShowWindow(d3d->ahwnd, SW_HIDE);
} else if (guion == 0) {
d3d->delayedfs = 1;
}
write_log(_T("fs guimode end\n"));
}
static int xD3D11_isenabled(int monid)
{
struct d3d11struct *d3d = &d3d11data[monid];
return d3d->m_device != NULL ? 2 : 0;
}
static bool xD3D_getvblankpos(int *vp)
{
*vp = 0;
return false;
}
static HDC xD3D_getDC(int monid, HDC hdc)
{
struct d3d11struct *d3d = &d3d11data[monid];
IDXGISurface1 *g_pSurface1 = NULL;
HRESULT hr;
if (hdc) {
RECT empty = { 0 };
g_pSurface1->ReleaseDC(&empty);
g_pSurface1->Release();
return NULL;
} else {
HDC g_hDC;
//Setup the device and and swapchain
hr = d3d->m_swapChain->GetBuffer(0, __uuidof(IDXGISurface1), (void**)&g_pSurface1);
if (FAILED(hr)) {
write_log(_T("GetDC GetBuffer() %08x\n"), hr);
return NULL;
}
hr = g_pSurface1->GetDC(FALSE, &g_hDC);
if (FAILED(hr)) {
write_log(_T("GetDC GetDC() %08x\n"), hr);
g_pSurface1->Release();
return NULL;
}
d3d->hdc_surface = g_pSurface1;
return g_hDC;
}
}
bool D3D11_capture(int monid, void **data, int *w, int *h, int *d, int *pitch, bool rendertarget)
{
struct d3d11struct *d3d = &d3d11data[monid];
HRESULT hr;
ID3D11Texture2D *screenshottexture = rendertarget ? d3d->screenshottexturert : d3d->screenshottexturetx;
if (!screenshottexture)
return false;
if (!w || !h) {
d3d->m_deviceContext->Unmap(screenshottexture, 0);
return true;
} else {
D3D11_MAPPED_SUBRESOURCE map;
ID3D11Resource* pSurface = NULL;
ID3D11Resource* pSurfaceRelease = NULL;
if (rendertarget) {
d3d->m_renderTargetView->GetResource(&pSurface);
pSurfaceRelease = pSurface;
} else {
pSurface = d3d->texture2dstaging;
}
if (pSurface) {
D3D11_TEXTURE2D_DESC desc;
d3d->m_deviceContext->CopyResource(screenshottexture, pSurface);
screenshottexture->GetDesc(&desc);
hr = d3d->m_deviceContext->Map(screenshottexture, 0, D3D11_MAP_READ, 0, &map);
if (FAILED(hr)) {
write_log(_T("Screenshot DeviceContext->Map() failed %08x\n"), hr);
return false;
}
if (pSurfaceRelease) {
pSurfaceRelease->Release();
}
*data = map.pData;
*pitch = map.RowPitch;
*w = desc.Width;
*h = desc.Height;
*d = d3d->hdr ? 36 : 24;
return true;
} else {
write_log(_T("Screenshot RenderTargetView->GetResource() failed\n"));
}
}
return false;
}
static void updatecursorsurface(int monid)
{
struct d3d11struct *d3d = &d3d11data[monid];
struct d3d11sprite *sp = &d3d->hwsprite;
int cx = (int)d3d->cursor_x;
int cy = (int)d3d->cursor_y;
int width = sp->width;
int height = sp->height;
int bw = d3d->m_bitmapWidth;
int bh = d3d->m_bitmapHeight;
if (sp->texture == NULL) {
return;
}
if (sp->updated && cx >= 0 && cy >= 0 && cx + width <= bw && cy + height <= bh) {
return;
}
sp->updated = false;
sp->empty = false;
D3D11_MAPPED_SUBRESOURCE map;
HRESULT hr = d3d->m_deviceContext->Map(sp->texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
if (SUCCEEDED(hr)) {
int pitch = map.RowPitch;
uae_u8 *b = (uae_u8 *)map.pData;
uae_u8 *s = sp->texbuf;
for (int h = 0; h < sp->height; h++) {
int w = width;
int x = 0;
if (cx + w > bw) {
w -= (cx + w) - bw;
}
if (cx < 0) {
x = -cx;
w -= -cx;
}
if (w <= 0 || cy + h > bh) {
memset(b, 0, width * 4);
} else {
if (x > 0) {
memset(b, 0, x * 4);
}
memcpy(b + x * 4, s + x * 4, w * 4);
if (w < width) {
memset(b + w * 4, 0, (width - w) * 4);
}
}
b += pitch;
s += width * 4;
}
d3d->m_deviceContext->Unmap(d3d->hwsprite.texture, 0);
if (cx >= 0 && cy >= 0 && cx + width <= bw && cy + height <= bh) {
sp->updated = true;
}
}
}
static bool xD3D_setcursor(int monid, int x, int y, int width, int height, float mx, float my, bool visible, bool noscale)
{
struct d3d11struct *d3d = &d3d11data[monid];
struct d3d11sprite *sp = &d3d->hwsprite;
//write_log(_T("setcursor %d %dx%d %dx%d %d %d\n"), monid, x, y, width, height, visible, noscale);
if (width < 0 || height < 0)
return true;
if (width && height) {
d3d->cursor_offset2_x = d3d->cursor_offset_x;
d3d->cursor_offset2_y = d3d->cursor_offset_y;
d3d->cursor_x = (float)x;
d3d->cursor_y = (float)y;
} else {
d3d->cursor_x = d3d->cursor_y = 0;
d3d->cursor_offset2_x = d3d->cursor_offset2_y = 0;
}
//write_log(_T("%.1fx%.1f %dx%d\n"), d3d->cursor_x, d3d->cursor_y, d3d->cursor_offset2_x, d3d->cursor_offset2_y);
float multx = d3d->xmult;
float multy = d3d->ymult;
setspritescaling(sp, mx * multx, my * multy);
sp->x = d3d->cursor_x * multx;
sp->y = d3d->cursor_y * multy;
sp->x += d3d->cursor_offset2_x * multx;
sp->y += d3d->cursor_offset2_y * multy;
//write_log(_T("-> %.1fx%.1f %.1f %.1f\n"), d3d->hwsprite.x, d3d->hwsprite.y, multx, multy);
d3d->cursor_v = visible;
sp->enabled = visible;
sp->bilinear = d3d->filterd3d->gfx_filter_bilinear;
updatecursorsurface(monid);
return true;
}
static uae_u8 *xD3D_setcursorsurface(int monid, bool query, int *pitch)
{
struct d3d11struct *d3d = &d3d11data[monid];
d3d->hwsprite.updated = false;
if (query) {
return d3d->hwsprite.empty ? NULL : d3d->hwsprite.texbuf;
}
if (!d3d->hwsprite.texbuf) {
return NULL;
}
if (pitch) {
*pitch = d3d->hwsprite.width * 4;
return d3d->hwsprite.texbuf;
}
return NULL;
}
static bool xD3D11_getscalerect(int monid, float *mx, float *my, float *sx, float *sy, int width, int height)
{
struct d3d11struct *d3d = &d3d11data[monid];
struct vidbuf_description *vidinfo = &adisplays[monid].gfxvidinfo;
if (!d3d->mask2texture.enabled)
return false;
float mw = (float)(d3d->mask2rect.right - d3d->mask2rect.left);
float mh = (float)(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 bool xD3D11_run(int monid)
{
struct d3d11struct *d3d = &d3d11data[monid];
if (xD3D11_quit(d3d))
return false;
if (recheck(d3d, monid))
return true;
return D3D11_resize_do(d3d, monid);
}
static bool xD3D11_extoverlay(struct extoverlay *ext, int monid)
{
struct d3d11struct *d3d = &d3d11data[monid];
struct d3doverlay *ov, *ovprev, *ov2;
struct d3d11sprite *s;
D3D11_MAPPED_SUBRESOURCE map;
HRESULT hr;
s = NULL;
ov = d3d->extoverlays;
ovprev = NULL;
while (ov) {
if (ov->id == ext->idx) {
s = &ov->s;
break;
}
ovprev = ov;
ov = ov->next;
}
if (!s && (ext->width <= 0 || ext->height <= 0))
return false;
if (!ext->data && s && (ext->width == 0 || ext->height == 0)) {
s->x = (float)ext->xpos;
s->y = (float)ext->ypos;
return true;
}
if (ov && s) {
if (ovprev) {
ovprev->next = ov->next;
} else {
d3d->extoverlays = ov->next;
}
freesprite(s);
xfree(ov);
if (ext->width <= 0 || ext->height <= 0)
return true;
}
if (ext->width <= 0 || ext->height <= 0)
return false;
ov = xcalloc(d3doverlay, 1);
s = &ov->s;
if (!allocsprite(d3d, s, ext->width, ext->height, true, false, false)) {
xfree(ov);
return false;
}
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;
}
s->enabled = true;
s->x = (float)ext->xpos;
s->y = (float)ext->ypos;
hr = d3d->m_deviceContext->Map(s->texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
if (SUCCEEDED(hr)) {
if (d3d->hdr) {
for (int y = 0; y < s->height; y++) {
uae_u32 *dp = (uae_u32*)((uae_u8 *)map.pData + y * map.RowPitch);
uae_u32 *sp = (uae_u32*)(ext->data + y * ext->width * 4);
for (int x = 0; x < s->width; x++) {
uae_u32 v = *sp++;
uae_u16 t = (v >> 24) * 10 / 7;
if (t > 255) {
t = 255;
}
*dp++ = (v & 0xffffff) | (t << 24);
}
}
} else {
for (int y = 0; y < s->height; y++) {
memcpy((uae_u8*)map.pData + y * map.RowPitch, ext->data + y * ext->width * 4, ext->width * 4);
}
}
d3d->m_deviceContext->Unmap(s->texture, 0);
}
return true;
}
void d3d11_select(void)
{
D3D_free = xD3D11_free;
D3D_init = xD3D11_init;
D3D_renderframe = xD3D11_renderframe;
D3D_alloctexture = xD3D11_alloctexture;
D3D_refresh = xD3D11_refresh;
D3D_restore = xD3D11_restore;
D3D_locktexture = xD3D11_locktexture;
D3D_unlocktexture = xD3D11_unlocktexture;
D3D_flushtexture = xD3D11_flushtexture;
D3D_showframe = xD3D11_showframe;
D3D_showframe_special = xD3D11_showframe_special;
D3D_guimode = xD3D11_guimode;
D3D_getDC = xD3D_getDC;
D3D_isenabled = xD3D11_isenabled;
D3D_clear = xD3D11_clear;
D3D_canshaders = xD3D11_canshaders;
D3D_goodenough = xD3D11_goodenough;
D3D_setcursor = xD3D_setcursor;
D3D_setcursorsurface = xD3D_setcursorsurface;
D3D_getrefreshrate = xD3D_getrefreshrate;
D3D_resize = xD3D11_resize;
D3D_change = xD3D11_change;
D3D_getscalerect = xD3D11_getscalerect;
D3D_run = xD3D11_run;
D3D_debug = xD3D11_debug;
D3D_led = xD3D11_led;
D3D_getscanline = NULL;
D3D_extoverlay = xD3D11_extoverlay;
D3D_paint = NULL;
}
void d3d_select(struct uae_prefs *p)
{
for (int i = 0; i < MAX_AMIGAMONITORS; i++) {
d3d11data[i].num = i;
}
if (p->gfx_api == 0)
gdi_select();
else if (p->gfx_api >= 2)
d3d11_select();
else
d3d9_select();
}