Merge branch 'dx9'

thanks to the DirectX 9 testing team:
- crappyfilename.exe
- EpicTyphlosion
- Mr. Hassium
- wbcbz7
- Yuzu4K
This commit is contained in:
tildearrow 2024-05-16 21:28:54 -05:00
commit a0efe1ec2c
31 changed files with 1010 additions and 54 deletions

View file

@ -972,17 +972,17 @@ if (WITH_RENDER_DX11)
endif()
endif()
#if (WITH_RENDER_DX9)
# if (WIN32)
# list(APPEND GUI_SOURCES src/gui/render/renderDX9.cpp)
# list(APPEND GUI_SOURCES extern/imgui_patched/backends/imgui_impl_dx9.cpp)
# list(APPEND DEPENDENCIES_DEFINES HAVE_RENDER_DX9)
# list(APPEND DEPENDENCIES_LIBRARIES d3d9)
# message(STATUS "UI render backend: DirectX 9")
# else()
# message(FATAL_ERROR "DirectX 9 render backend only for Windows!")
# endif()
#endif()
if (WITH_RENDER_DX9)
if (WIN32)
list(APPEND GUI_SOURCES src/gui/render/renderDX9.cpp)
list(APPEND GUI_SOURCES extern/imgui_patched/backends/imgui_impl_dx9.cpp)
list(APPEND DEPENDENCIES_DEFINES HAVE_RENDER_DX9)
list(APPEND DEPENDENCIES_LIBRARIES d3d9)
message(STATUS "UI render backend: DirectX 9")
else()
message(FATAL_ERROR "DirectX 9 render backend only for Windows!")
endif()
endif()
if (WITH_RENDER_METAL)
if (APPLE)

View file

@ -170,11 +170,12 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
{
if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }
bd->IndexBufferSize = draw_data->TotalIdxCount + 10000;
if (bd->pd3dDevice->CreateIndexBuffer(bd->IndexBufferSize * sizeof(ImDrawIdx), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &bd->pIB, nullptr) < 0)
if (bd->pd3dDevice->CreateIndexBuffer(bd->IndexBufferSize * sizeof(unsigned short), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &bd->pIB, nullptr) < 0)
return;
}
// Backup the DX9 state
/*
IDirect3DStateBlock9* d3d9_state_block = nullptr;
if (bd->pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d9_state_block) < 0)
return;
@ -182,26 +183,28 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
{
d3d9_state_block->Release();
return;
}
}*/
// Backup the DX9 transform (DX9 documentation suggests that it is included in the StateBlock but it doesn't appear to)
/*
D3DMATRIX last_world, last_view, last_projection;
bd->pd3dDevice->GetTransform(D3DTS_WORLD, &last_world);
bd->pd3dDevice->GetTransform(D3DTS_VIEW, &last_view);
bd->pd3dDevice->GetTransform(D3DTS_PROJECTION, &last_projection);
*/
// Allocate buffers
CUSTOMVERTEX* vtx_dst;
ImDrawIdx* idx_dst;
unsigned short* idx_dst;
if (bd->pVB->Lock(0, (UINT)(draw_data->TotalVtxCount * sizeof(CUSTOMVERTEX)), (void**)&vtx_dst, D3DLOCK_DISCARD) < 0)
{
d3d9_state_block->Release();
//d3d9_state_block->Release();
return;
}
if (bd->pIB->Lock(0, (UINT)(draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (void**)&idx_dst, D3DLOCK_DISCARD) < 0)
if (bd->pIB->Lock(0, (UINT)(draw_data->TotalIdxCount * sizeof(unsigned short)), (void**)&idx_dst, D3DLOCK_DISCARD) < 0)
{
bd->pVB->Unlock();
d3d9_state_block->Release();
//d3d9_state_block->Release();
return;
}
@ -224,7 +227,14 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
vtx_dst++;
vtx_src++;
}
if (sizeof(ImDrawIdx) == sizeof(unsigned short)) {
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
} else {
// slower, but works on VIA
for (int i=0; i<cmd_list->IdxBuffer.Size; i++) {
idx_dst[i]=cmd_list->IdxBuffer.Data[i];
}
}
idx_dst += cmd_list->IdxBuffer.Size;
}
bd->pVB->Unlock();
@ -282,13 +292,18 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
bd->pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 0, 0, 0);
// Restore the DX9 transform
// don't. I like this transform.
/*
bd->pd3dDevice->SetTransform(D3DTS_WORLD, &last_world);
bd->pd3dDevice->SetTransform(D3DTS_VIEW, &last_view);
bd->pd3dDevice->SetTransform(D3DTS_PROJECTION, &last_projection);
*/
// Restore the DX9 state
/*
d3d9_state_block->Apply();
d3d9_state_block->Release();
*/
}
bool ImGui_ImplDX9_Init(IDirect3DDevice9* device)
@ -391,13 +406,15 @@ void ImGui_ImplDX9_InvalidateDeviceObjects()
ImGui_ImplDX9_InvalidateDeviceObjectsForPlatformWindows();
}
void ImGui_ImplDX9_NewFrame()
bool ImGui_ImplDX9_NewFrame()
{
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplDX9_Init()?");
if (!bd->FontTexture)
ImGui_ImplDX9_CreateDeviceObjects();
return ImGui_ImplDX9_CreateDeviceObjects();
return true;
}
//--------------------------------------------------------------------------------------------------------
@ -506,9 +523,7 @@ static void ImGui_ImplDX9_RenderWindow(ImGuiViewport* viewport, void*)
static void ImGui_ImplDX9_SwapBuffers(ImGuiViewport* viewport, void*)
{
ImGui_ImplDX9_ViewportData* vd = (ImGui_ImplDX9_ViewportData*)viewport->RendererUserData;
HRESULT hr = vd->SwapChain->Present(nullptr, nullptr, vd->d3dpp.hDeviceWindow, nullptr, 0);
// Let main application handle D3DERR_DEVICELOST by resetting the device.
IM_ASSERT(hr == D3D_OK || hr == D3DERR_DEVICELOST);
vd->SwapChain->Present(nullptr, nullptr, vd->d3dpp.hDeviceWindow, nullptr, 0);
}
static void ImGui_ImplDX9_InitPlatformInterface()

View file

@ -19,7 +19,7 @@ struct IDirect3DDevice9;
IMGUI_IMPL_API bool ImGui_ImplDX9_Init(IDirect3DDevice9* device);
IMGUI_IMPL_API void ImGui_ImplDX9_Shutdown();
IMGUI_IMPL_API void ImGui_ImplDX9_NewFrame();
IMGUI_IMPL_API bool ImGui_ImplDX9_NewFrame();
IMGUI_IMPL_API void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data);
// Use if you want to reset your rendering device without losing Dear ImGui state.

View file

@ -15,7 +15,7 @@ fi
cd win32build
# TODO: potential Arch-ism?
i686-w64-mingw32-cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_FLAGS="-O2 -march=i586" -DCMAKE_CXX_FLAGS="-O2 -Wall -Wextra -Wno-unused-parameter -Wno-cast-function-type -march=i586" -DBUILD_SHARED_LIBS=OFF -DSUPPORT_XP=OFF -DWITH_RENDER_DX11=ON -DUSE_BACKWARD=ON -DSDL_SSE2=OFF -DSDL_SSE3=OFF -DENABLE_SSE=OFF -DENABLE_SSE2=OFF -DENABLE_AVX=OFF -DENABLE_AVX2=OFF .. || exit 1
i686-w64-mingw32-cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_FLAGS="-O2 -march=i586" -DCMAKE_CXX_FLAGS="-O2 -Wall -Wextra -Wno-unused-parameter -Wno-cast-function-type -march=i586" -DBUILD_SHARED_LIBS=OFF -DSUPPORT_XP=OFF -DWITH_RENDER_DX11=ON -DUSE_BACKWARD=ON -DSDL_SSE=OFF -DSDL_SSE2=OFF -DSDL_SSE3=OFF -DENABLE_SSE=OFF -DENABLE_SSE2=OFF -DENABLE_AVX=OFF -DENABLE_AVX2=OFF .. || exit 1
make -j8 || exit 1
cd ..

View file

@ -15,7 +15,7 @@ fi
cd xpbuild
# TODO: potential Arch-ism?
i686-w64-mingw32-cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_FLAGS="-O2" -DCMAKE_CXX_FLAGS="-O2 -Wall -Wextra -Wno-unused-parameter -Wno-cast-function-type" -DBUILD_SHARED_LIBS=OFF -DSUPPORT_XP=ON -DWITH_RENDER_DX11=OFF -DSDL_SSE2=OFF -DSDL_SSE3=OFF -DENABLE_SSE=OFF -DENABLE_SSE2=OFF -DENABLE_AVX=OFF -DENABLE_AVX2=OFF -DUSE_BACKWARD=ON .. || exit 1
i686-w64-mingw32-cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_FLAGS="-O2" -DCMAKE_CXX_FLAGS="-O2 -Wall -Wextra -Wno-unused-parameter -Wno-cast-function-type" -DBUILD_SHARED_LIBS=OFF -DSUPPORT_XP=ON -DWITH_RENDER_DX11=OFF -DSDL_SSE=OFF -DSDL_SSE2=OFF -DSDL_SSE3=OFF -DENABLE_SSE=OFF -DENABLE_SSE2=OFF -DENABLE_AVX=OFF -DENABLE_AVX2=OFF -DUSE_BACKWARD=ON -DCONSOLE_SUBSYSTEM=OFF .. || exit 1
make -j8 || exit 1
cd ..

View file

@ -52,10 +52,10 @@ class DivWorkPool;
#define EXTERN_BUSY_BEGIN_SOFT e->softLocked=true; e->isBusy.lock();
#define EXTERN_BUSY_END e->isBusy.unlock(); e->softLocked=false;
//#define DIV_UNSTABLE
#define DIV_UNSTABLE
#define DIV_VERSION "0.6.3"
#define DIV_ENGINE_VERSION 201
#define DIV_VERSION "DX9 Test X"
#define DIV_ENGINE_VERSION 211
// for imports
#define DIV_VERSION_MOD 0xff01
#define DIV_VERSION_FC 0xff02

View file

@ -212,7 +212,7 @@ void FurnaceGUI::drawChanOsc() {
if (chanOscUseGrad) {
if (chanOscGradTex==NULL) {
chanOscGradTex=rend->createTexture(true,chanOscGrad.width,chanOscGrad.height);
chanOscGradTex=rend->createTexture(true,chanOscGrad.width,chanOscGrad.height,true,bestTexFormat);
if (chanOscGradTex==NULL) {
logE("error while creating gradient texture!");

View file

@ -614,7 +614,7 @@ void FurnaceGUI::drawDebug() {
ImGui::Text("Create and Destroy 128 Textures");
if (ImGui::Button("No Write")) {
for (int i=0; i<128; i++) {
FurnaceGUITexture* t=rend->createTexture(false,2048,2048);
FurnaceGUITexture* t=rend->createTexture(false,2048,2048,true,bestTexFormat);
if (t==NULL) {
showError(fmt::sprintf("Failure! %d",i));
break;
@ -628,7 +628,7 @@ void FurnaceGUI::drawDebug() {
data[i]=rand();
}
for (int i=0; i<128; i++) {
FurnaceGUITexture* t=rend->createTexture(false,2048,2048);
FurnaceGUITexture* t=rend->createTexture(false,2048,2048,true,bestTexFormat);
if (t==NULL) {
showError(fmt::sprintf("Failure! %d",i));
break;
@ -642,7 +642,7 @@ void FurnaceGUI::drawDebug() {
unsigned char* data=NULL;
int pitch=0;
for (int i=0; i<128; i++) {
FurnaceGUITexture* t=rend->createTexture(false,2048,2048);
FurnaceGUITexture* t=rend->createTexture(false,2048,2048,true,bestTexFormat);
if (t==NULL) {
showError(fmt::sprintf("Failure! %d",i));
break;

View file

@ -7091,6 +7091,18 @@ bool FurnaceGUI::init() {
}
logV("render backend started");
// set best texture format
unsigned int availTexFormats=rend->getTextureFormats();
if (availTexFormats&GUI_TEXFORMAT_ABGR32) {
bestTexFormat=GUI_TEXFORMAT_ABGR32;
} else if (availTexFormats&GUI_TEXFORMAT_ARGB32) {
bestTexFormat=GUI_TEXFORMAT_ARGB32;
} else if (availTexFormats&GUI_TEXFORMAT_RGBA32) {
bestTexFormat=GUI_TEXFORMAT_RGBA32;
} else if (availTexFormats&GUI_TEXFORMAT_BGRA32) {
bestTexFormat=GUI_TEXFORMAT_BGRA32;
}
// try acquiring the canvas size
if (!rend->getOutputSize(canvasW,canvasH)) {
logW("could not get renderer output size!");

View file

@ -1443,6 +1443,14 @@ struct FurnaceGUIWaveSizeEntry {
sys(NULL) {}
};
enum FurnaceGUITextureFormat: unsigned int {
GUI_TEXFORMAT_UNKNOWN=0,
GUI_TEXFORMAT_ABGR32=1,
GUI_TEXFORMAT_ARGB32=2,
GUI_TEXFORMAT_BGRA32=4,
GUI_TEXFORMAT_RGBA32=8,
};
class FurnaceGUITexture {
};
@ -1482,10 +1490,12 @@ class FurnaceGUIRender {
virtual ImTextureID getTextureID(FurnaceGUITexture* which);
virtual float getTextureU(FurnaceGUITexture* which);
virtual float getTextureV(FurnaceGUITexture* which);
virtual FurnaceGUITextureFormat getTextureFormat(FurnaceGUITexture* which);
virtual bool isTextureValid(FurnaceGUITexture* which);
virtual bool lockTexture(FurnaceGUITexture* which, void** data, int* pitch);
virtual bool unlockTexture(FurnaceGUITexture* which);
virtual bool updateTexture(FurnaceGUITexture* which, void* data, int pitch);
virtual FurnaceGUITexture* createTexture(bool dynamic, int width, int height, bool interpolate=true);
virtual FurnaceGUITexture* createTexture(bool dynamic, int width, int height, bool interpolate=true, FurnaceGUITextureFormat format=GUI_TEXFORMAT_ABGR32);
virtual bool destroyTexture(FurnaceGUITexture* which);
virtual void setTextureBlendMode(FurnaceGUITexture* which, FurnaceGUIBlendMode mode);
virtual void setBlendMode(FurnaceGUIBlendMode mode);
@ -1504,6 +1514,7 @@ class FurnaceGUIRender {
virtual int getWindowFlags();
virtual int getMaxTextureWidth();
virtual int getMaxTextureHeight();
virtual unsigned int getTextureFormats();
virtual const char* getBackendName();
virtual const char* getVendorName();
virtual const char* getDeviceName();
@ -1543,6 +1554,7 @@ class FurnaceGUI {
FurnaceGUIRenderBackend renderBackend;
FurnaceGUIRender* rend;
FurnaceGUITextureFormat bestTexFormat;
SDL_Window* sdlWin;
SDL_Haptic* vibrator;

View file

@ -53,8 +53,20 @@ FurnaceGUITexture* FurnaceGUI::getTexture(FurnaceGUIImages image, FurnaceGUIBlen
if (img->data==NULL) return NULL;
if (img->width<=0 || img->height<=0) return NULL;
bool createTex=false;
if (img->tex==NULL) {
img->tex=rend->createTexture(false,img->width,img->height);
createTex=true;
} else {
if (!rend->isTextureValid(img->tex)) {
rend->destroyTexture(img->tex);
img->tex=NULL;
createTex=true;
}
}
if (createTex) {
img->tex=rend->createTexture(false,img->width,img->height,true,bestTexFormat);
if (img->tex==NULL) {
logE("error while creating image %d texture! %s",(int)image,SDL_GetError());
return NULL;
@ -101,6 +113,44 @@ FurnaceGUIImage* FurnaceGUI::getImage(FurnaceGUIImages image) {
}
#endif
if (ret->ch==4) {
size_t total=ret->width*ret->height*ret->ch;
switch (bestTexFormat) {
case GUI_TEXFORMAT_ARGB32:
for (size_t i=0; i<total; i+=4) {
ret->data[i]^=ret->data[i|2];
ret->data[i|2]^=ret->data[i];
ret->data[i]^=ret->data[i|2];
}
break;
case GUI_TEXFORMAT_BGRA32:
for (size_t i=0; i<total; i+=4) {
ret->data[i]^=ret->data[i|3];
ret->data[i|3]^=ret->data[i];
ret->data[i]^=ret->data[i|3];
ret->data[i|1]^=ret->data[i|2];
ret->data[i|2]^=ret->data[i|1];
ret->data[i|1]^=ret->data[i|2];
ret->data[i|1]^=ret->data[i|3];
ret->data[i|3]^=ret->data[i|1];
ret->data[i|1]^=ret->data[i|3];
}
break;
case GUI_TEXFORMAT_RGBA32:
for (size_t i=0; i<total; i+=4) {
ret->data[i]^=ret->data[i|3];
ret->data[i|3]^=ret->data[i];
ret->data[i]^=ret->data[i|3];
ret->data[i|1]^=ret->data[i|2];
ret->data[i|2]^=ret->data[i|1];
ret->data[i|1]^=ret->data[i|2];
}
break;
default:
break;
}
}
images[image]=ret;
}

View file

@ -27,6 +27,8 @@ void FurnaceGUI::drawImage(ImDrawList* dl, FurnaceGUIImages image, const ImVec2&
FurnaceGUIImage* imgI=getImage(image);
FurnaceGUITexture* img=getTexture(image);
if (img==NULL) return;
float squareSize=MAX(introMax.x-introMin.x,introMax.y-introMin.y);
float uDiff=uvMax.x-uvMin.x;
float vDiff=uvMax.y-uvMin.y;

View file

@ -31,6 +31,9 @@
#ifdef HAVE_RENDER_DX11
#include "render/renderDX11.h"
#endif
#ifdef HAVE_RENDER_DX9
#include "render/renderDX9.h"
#endif
#ifdef HAVE_RENDER_METAL
#include "render/renderMetal.h"
#endif

View file

@ -31,6 +31,14 @@ float FurnaceGUIRender::getTextureV(FurnaceGUITexture* which) {
return 1.0;
}
FurnaceGUITextureFormat FurnaceGUIRender::getTextureFormat(FurnaceGUITexture* which) {
return GUI_TEXFORMAT_UNKNOWN;
}
bool FurnaceGUIRender::isTextureValid(FurnaceGUITexture* which) {
return (which!=NULL);
}
bool FurnaceGUIRender::lockTexture(FurnaceGUITexture* which, void** data, int* pitch) {
return false;
}
@ -43,7 +51,7 @@ bool FurnaceGUIRender::updateTexture(FurnaceGUITexture* which, void* data, int p
return false;
}
FurnaceGUITexture* FurnaceGUIRender::createTexture(bool dynamic, int width, int height, bool interpolate) {
FurnaceGUITexture* FurnaceGUIRender::createTexture(bool dynamic, int width, int height, bool interpolate, FurnaceGUITextureFormat format) {
return NULL;
}
@ -109,6 +117,10 @@ int FurnaceGUIRender::getMaxTextureHeight() {
return 0;
}
unsigned int FurnaceGUIRender::getTextureFormats() {
return 0;
}
const char* FurnaceGUIRender::getBackendName() {
return "Dummy";
}

View file

@ -75,6 +75,7 @@ class FurnaceDXTexture: public FurnaceGUITexture {
ID3D11Texture2D* tex;
ID3D11ShaderResourceView* view;
int width, height;
FurnaceGUITextureFormat format;
unsigned char* lockedData;
bool dynamic;
FurnaceDXTexture():
@ -82,6 +83,7 @@ class FurnaceDXTexture: public FurnaceGUITexture {
view(NULL),
width(0),
height(0),
format(GUI_TEXFORMAT_UNKNOWN),
lockedData(NULL),
dynamic(false) {}
};
@ -147,6 +149,11 @@ ImTextureID FurnaceGUIRenderDX11::getTextureID(FurnaceGUITexture* which) {
return (ImTextureID)t->view;
}
FurnaceGUITextureFormat FurnaceGUIRenderDX11::getTextureFormat(FurnaceGUITexture* which) {
FurnaceDXTexture* t=(FurnaceDXTexture*)which;
return t->format;
}
bool FurnaceGUIRenderDX11::lockTexture(FurnaceGUITexture* which, void** data, int* pitch) {
FurnaceDXTexture* t=(FurnaceDXTexture*)which;
if (t->lockedData!=NULL) return false;
@ -200,7 +207,7 @@ bool FurnaceGUIRenderDX11::updateTexture(FurnaceGUITexture* which, void* data, i
return true;
}
FurnaceGUITexture* FurnaceGUIRenderDX11::createTexture(bool dynamic, int width, int height, bool interpolate) {
FurnaceGUITexture* FurnaceGUIRenderDX11::createTexture(bool dynamic, int width, int height, bool interpolate, FurnaceGUITextureFormat format) {
D3D11_TEXTURE2D_DESC texDesc;
D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
ID3D11Texture2D* tex=NULL;
@ -214,7 +221,17 @@ FurnaceGUITexture* FurnaceGUIRenderDX11::createTexture(bool dynamic, int width,
texDesc.Height=height;
texDesc.MipLevels=1;
texDesc.ArraySize=1;
texDesc.Format=DXGI_FORMAT_R8G8B8A8_UNORM; // ???
switch (format) {
case GUI_TEXFORMAT_ABGR32:
texDesc.Format=DXGI_FORMAT_R8G8B8A8_UNORM;
break;
case GUI_TEXFORMAT_ARGB32:
texDesc.Format=DXGI_FORMAT_B8G8R8A8_UNORM;
break;
default:
logE("unsupported texture format!");
return NULL;
}
texDesc.SampleDesc.Count=1;
texDesc.SampleDesc.Quality=0;
texDesc.Usage=dynamic?D3D11_USAGE_DYNAMIC:D3D11_USAGE_DEFAULT;
@ -246,6 +263,7 @@ FurnaceGUITexture* FurnaceGUIRenderDX11::createTexture(bool dynamic, int width,
ret->tex=tex;
ret->view=view;
ret->dynamic=dynamic;
ret->format=format;
return ret;
}
@ -377,6 +395,10 @@ int FurnaceGUIRenderDX11::getMaxTextureHeight() {
return maxHeight;
}
unsigned int FurnaceGUIRenderDX11::getTextureFormats() {
return GUI_TEXFORMAT_ABGR32|GUI_TEXFORMAT_ARGB32;
}
const char* FurnaceGUIRenderDX11::getBackendName() {
return "DirectX 11";
}

View file

@ -64,10 +64,11 @@ class FurnaceGUIRenderDX11: public FurnaceGUIRender {
public:
ImTextureID getTextureID(FurnaceGUITexture* which);
FurnaceGUITextureFormat getTextureFormat(FurnaceGUITexture* which);
bool lockTexture(FurnaceGUITexture* which, void** data, int* pitch);
bool unlockTexture(FurnaceGUITexture* which);
bool updateTexture(FurnaceGUITexture* which, void* data, int pitch);
FurnaceGUITexture* createTexture(bool dynamic, int width, int height, bool interpolate=true);
FurnaceGUITexture* createTexture(bool dynamic, int width, int height, bool interpolate=true, FurnaceGUITextureFormat format=GUI_TEXFORMAT_ABGR32);
bool destroyTexture(FurnaceGUITexture* which);
void setTextureBlendMode(FurnaceGUITexture* which, FurnaceGUIBlendMode mode);
void setBlendMode(FurnaceGUIBlendMode mode);
@ -84,6 +85,7 @@ class FurnaceGUIRenderDX11: public FurnaceGUIRender {
int getWindowFlags();
int getMaxTextureWidth();
int getMaxTextureHeight();
unsigned int getTextureFormats();
const char* getBackendName();
const char* getVendorName();
const char* getDeviceName();

View file

@ -0,0 +1,592 @@
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2024 tildearrow and contributors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#define INCLUDE_D3D9
#include "renderDX9.h"
#include <SDL_syswm.h>
#include "backends/imgui_impl_dx9.h"
#include "../../ta-log.h"
#include "../../utfutils.h"
#include "../engine/bsr.h"
class FurnaceDX9Texture: public FurnaceGUITexture {
public:
IDirect3DTexture9* tex;
IDirect3DTexture9* texPre;
int width, height, widthReal, heightReal;
FurnaceGUITextureFormat format;
unsigned char* lockedData;
bool dynamic;
FurnaceDX9Texture():
tex(NULL),
texPre(NULL),
width(0),
height(0),
widthReal(0),
heightReal(0),
format(GUI_TEXFORMAT_UNKNOWN),
lockedData(NULL),
dynamic(false) {}
};
struct FurnaceGUIRenderDX9Private {
D3DPRESENT_PARAMETERS present;
std::vector<FurnaceDX9Texture*> texPool;
};
struct WipeVertex {
float x, y, z;
unsigned int color;
WipeVertex(float _x, float _y, float _z, unsigned int c):
x(_x),
y(_y),
z(_z),
color(c) {}
WipeVertex():
x(0),
y(0),
z(0),
color(0) {}
};
ImTextureID FurnaceGUIRenderDX9::getTextureID(FurnaceGUITexture* which) {
FurnaceDX9Texture* t=(FurnaceDX9Texture*)which;
return (ImTextureID)t->tex;
}
float FurnaceGUIRenderDX9::getTextureU(FurnaceGUITexture* which) {
FurnaceDX9Texture* t=(FurnaceDX9Texture*)which;
if (which==NULL) return 0.0;
if (t->widthReal<1) return 0.0f;
return (float)t->width/(float)t->widthReal;
}
float FurnaceGUIRenderDX9::getTextureV(FurnaceGUITexture* which) {
FurnaceDX9Texture* t=(FurnaceDX9Texture*)which;
if (which==NULL) return 0.0;
if (t->heightReal<1) return 0.0f;
return (float)t->height/(float)t->heightReal;
}
FurnaceGUITextureFormat FurnaceGUIRenderDX9::getTextureFormat(FurnaceGUITexture* which) {
FurnaceDX9Texture* t=(FurnaceDX9Texture*)which;
return t->format;
}
bool FurnaceGUIRenderDX9::isTextureValid(FurnaceGUITexture* which) {
if (which==NULL) return false;
FurnaceDX9Texture* t=(FurnaceDX9Texture*)which;
return (t->tex!=NULL);
}
bool FurnaceGUIRenderDX9::lockTexture(FurnaceGUITexture* which, void** data, int* pitch) {
FurnaceDX9Texture* t=(FurnaceDX9Texture*)which;
D3DLOCKED_RECT lockedRect;
HRESULT result=t->tex->LockRect(0,&lockedRect,NULL,D3DLOCK_DISCARD);
if (result!=D3D_OK) {
logW("could not lock texture!");
return false;
}
*data=lockedRect.pBits;
*pitch=lockedRect.Pitch;
return true;
}
bool FurnaceGUIRenderDX9::unlockTexture(FurnaceGUITexture* which) {
FurnaceDX9Texture* t=(FurnaceDX9Texture*)which;
HRESULT result=t->tex->UnlockRect(0);
if (result!=D3D_OK) {
logW("could not unlock texture!");
return false;
}
return true;
}
bool FurnaceGUIRenderDX9::updateTexture(FurnaceGUITexture* which, void* data, int pitch) {
FurnaceDX9Texture* t=(FurnaceDX9Texture*)which;
IDirect3DTexture9* crap=NULL;
if (t->texPre==NULL) {
// update by locking
if (!t->dynamic) {
logW("updating static texture but texPre does not exist!");
return false;
}
crap=t->tex;
} else {
// update by calling UpdateTexture
crap=t->texPre;
}
D3DLOCKED_RECT lockedRect;
HRESULT result=crap->LockRect(0,&lockedRect,NULL,D3DLOCK_DISCARD);
if (result!=D3D_OK) {
logW("could not update texture (lock)! %.8x",result);
return false;
}
if (lockedRect.Pitch==pitch) {
memcpy(lockedRect.pBits,data,pitch*t->height);
} else {
unsigned char* ucData=(unsigned char*)data;
unsigned char* d=(unsigned char*)lockedRect.pBits;
int srcPos=0;
int destPos=0;
for (int i=0; i<t->height; i++) {
memcpy(&d[destPos],&ucData[srcPos],pitch);
srcPos+=pitch;
destPos+=lockedRect.Pitch;
}
}
crap->UnlockRect(0);
if (t->texPre!=NULL) {
result=t->tex->AddDirtyRect(NULL);
if (result!=D3D_OK) {
logW("could not taint texture! %.8x",result);
}
result=device->UpdateTexture(t->texPre,t->tex);
if (result!=D3D_OK) {
logW("could not update texture! %.8x",result);
return false;
}
}
return true;
}
FurnaceGUITexture* FurnaceGUIRenderDX9::createTexture(bool dynamic, int width, int height, bool interpolate, FurnaceGUITextureFormat format) {
IDirect3DTexture9* tex=NULL;
IDirect3DTexture9* texPre=NULL;
int widthReal=width;
int heightReal=height;
if (format!=GUI_TEXFORMAT_ARGB32) {
logE("unsupported texture format!");
return NULL;
}
if ((widthReal&(widthReal-1))!=0) {
widthReal=1<<bsr(width);
}
if ((heightReal&(heightReal-1))!=0) {
heightReal=1<<bsr(height);
}
if (squareTex) {
if (widthReal>heightReal) {
heightReal=widthReal;
} else {
widthReal=heightReal;
}
}
logV("width: %d (requested)... %d (actual)",width,widthReal);
logV("height: %d (requested)... %d (actual)",height,heightReal);
if (!supportsDynamicTex) dynamic=false;
HRESULT result=device->CreateTexture(widthReal,heightReal,1,dynamic?D3DUSAGE_DYNAMIC:0,D3DFMT_A8R8G8B8,D3DPOOL_DEFAULT,&tex,NULL);
if (result!=D3D_OK) {
logW("could not create texture! %.8x",result);
return NULL;
}
if (!dynamic) {
HRESULT result=device->CreateTexture(widthReal,heightReal,1,0,D3DFMT_A8R8G8B8,D3DPOOL_SYSTEMMEM,&texPre,NULL);
if (result!=D3D_OK) {
logW("could not create pre-texture! %.8x",result);
tex->Release();
return NULL;
}
}
FurnaceDX9Texture* ret=new FurnaceDX9Texture;
ret->width=width;
ret->height=height;
ret->widthReal=widthReal;
ret->heightReal=heightReal;
ret->tex=tex;
ret->texPre=texPre;
ret->dynamic=dynamic;
ret->format=format;
priv->texPool.push_back(ret);
return ret;
}
bool FurnaceGUIRenderDX9::destroyTexture(FurnaceGUITexture* which) {
FurnaceDX9Texture* t=(FurnaceDX9Texture*)which;
if (t->texPre!=NULL) t->texPre->Release();
if (t->tex!=NULL) t->tex->Release();
delete t;
for (size_t i=0; i<priv->texPool.size(); i++) {
if (priv->texPool[i]==t) {
priv->texPool.erase(priv->texPool.begin()+i);
break;
}
}
return true;
}
void FurnaceGUIRenderDX9::setTextureBlendMode(FurnaceGUITexture* which, FurnaceGUIBlendMode mode) {
}
void FurnaceGUIRenderDX9::setBlendMode(FurnaceGUIBlendMode mode) {
}
void FurnaceGUIRenderDX9::resized(const SDL_Event& ev) {
mustResize=true;
outW=ev.window.data1;
outH=ev.window.data2;
}
void FurnaceGUIRenderDX9::clear(ImVec4 color) {
device->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,ImGui::ColorConvertFloat4ToU32(color),0,0);
}
void FurnaceGUIRenderDX9::present() {
if (inScene) {
device->EndScene();
inScene=false;
}
if (device->Present(NULL,NULL,NULL,NULL)==D3DERR_DEVICEREMOVED) {
logI("device is gone");
dead=true;
return;
}
if (mustResize) {
logI("DX9: resizing buffers");
ImGui_ImplDX9_InvalidateDeviceObjects();
if (wipeBuf) {
wipeBuf->Release();
wipeBuf=NULL;
}
for (FurnaceDX9Texture* i: priv->texPool) {
if (i->tex) {
i->tex->Release();
i->tex=NULL;
}
if (i->texPre) {
i->texPre->Release();
i->texPre=NULL;
}
}
priv->present.BackBufferWidth=outW;
priv->present.BackBufferHeight=outH;
priv->present.BackBufferCount=1;
HRESULT result=device->Reset(&priv->present);
priv->present.BackBufferWidth=outW;
priv->present.BackBufferHeight=outH;
priv->present.BackBufferCount=1;
if (result==D3DERR_INVALIDCALL) {
logE("OH NO");
dead=true;
mustResize=false;
return;
}
ImGui_ImplDX9_CreateDeviceObjects();
result=device->CreateVertexBuffer(sizeof(WipeVertex)*4,0,D3DFVF_XYZ|D3DFVF_DIFFUSE,D3DPOOL_DEFAULT,&wipeBuf,NULL);
if (result!=D3D_OK) {
logE("could not create wipe buffer! %.8x",result);
}
mustResize=false;
}
}
bool FurnaceGUIRenderDX9::newFrame() {
return ImGui_ImplDX9_NewFrame();
}
bool FurnaceGUIRenderDX9::canVSync() {
return supportsVSync;
}
void FurnaceGUIRenderDX9::createFontsTexture() {
ImGui_ImplDX9_CreateDeviceObjects();
}
void FurnaceGUIRenderDX9::destroyFontsTexture() {
ImGui_ImplDX9_InvalidateDeviceObjects();
}
void FurnaceGUIRenderDX9::renderGUI() {
if (!inScene) {
HRESULT result=device->BeginScene();
if (result!=D3D_OK) {
logW("couldn't render GUI! %.8x",result);
return;
}
inScene=true;
}
ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());
}
void FurnaceGUIRenderDX9::wipe(float alpha) {
if (wipeBuf==NULL) return;
logV("WIPE...");
if (!inScene) {
HRESULT result=device->BeginScene();
if (result!=D3D_OK) {
logW("couldn't render GUI! %.8x",result);
return;
}
inScene=true;
}
D3DVIEWPORT9 view;
view.X=0;
view.Y=0;
view.Width=outW;
view.Height=outH;
view.MinZ=0.0f;
view.MaxZ=1.0f;
HRESULT result=device->SetViewport(&view);
if (result!=D3D_OK) {
logW("could not set viewport! %.8x",result);
}
unsigned char alphaU=alpha*255.0f;
unsigned int color=alphaU<<24;
void* lockedData;
WipeVertex vertex[4];
vertex[0]=WipeVertex(0,0,0,color);
vertex[1]=WipeVertex(outW,0,0,color);
vertex[2]=WipeVertex(outW,outH,0,color);
vertex[3]=WipeVertex(0,outH,0,color);
result=wipeBuf->Lock(0,0,&lockedData,D3DLOCK_DISCARD);
if (result==D3D_OK) {
memcpy(lockedData,vertex,sizeof(WipeVertex)*4);
wipeBuf->Unlock();
result=device->SetRenderState(D3DRS_SCISSORTESTENABLE,FALSE);
if (result!=D3D_OK) {
logE("SHIT! scissor, %.8x",result);
}
result=device->SetTexture(0,NULL);
if (result!=D3D_OK) {
logE("SHIT! set texture, %.8x",result);
}
result=device->SetStreamSource(0,wipeBuf,0,sizeof(WipeVertex));
if (result!=D3D_OK) {
logE("SHIT! set stream source, %.8x",result);
}
result=device->SetTexture(0,NULL);
if (result!=D3D_OK) {
logE("SHIT! set texture, %.8x",result);
}
result=device->SetFVF(D3DFVF_XYZ|D3DFVF_DIFFUSE);
if (result!=D3D_OK) {
logE("SHIT! set FVF, %.8x",result);
}
result=device->DrawPrimitive(D3DPT_TRIANGLEFAN,0,2);
if (result!=D3D_OK) {
logE("SHIT! draw primitive, %.8x",result);
}
} else {
logE("SHIT! lock, %.8x",result);
}
}
bool FurnaceGUIRenderDX9::getOutputSize(int& w, int& h) {
w=outW;
h=outH;
return true;
}
int FurnaceGUIRenderDX9::getWindowFlags() {
return 0;
}
int FurnaceGUIRenderDX9::getMaxTextureWidth() {
return maxWidth;
}
int FurnaceGUIRenderDX9::getMaxTextureHeight() {
return maxHeight;
}
unsigned int FurnaceGUIRenderDX9::getTextureFormats() {
return GUI_TEXFORMAT_ARGB32;
}
const char* FurnaceGUIRenderDX9::getBackendName() {
return "DirectX 9";
}
const char* FurnaceGUIRenderDX9::getVendorName() {
return vendorName.c_str();
}
const char* FurnaceGUIRenderDX9::getDeviceName() {
return deviceName.c_str();
}
const char* FurnaceGUIRenderDX9::getAPIVersion() {
return apiVersion.c_str();
}
void FurnaceGUIRenderDX9::setSwapInterval(int swapInt) {
swapInterval=swapInt;
}
void FurnaceGUIRenderDX9::preInit(const DivConfig& conf) {
}
bool FurnaceGUIRenderDX9::init(SDL_Window* win, int swapInt) {
D3DADAPTER_IDENTIFIER9 adapterInfo;
SDL_SysWMinfo sysWindow;
SDL_VERSION(&sysWindow.version);
if (SDL_GetWindowWMInfo(win,&sysWindow)==SDL_FALSE) {
logE("could not get window WM info! %s",SDL_GetError());
return false;
}
HWND window=(HWND)sysWindow.info.win.window;
iface=Direct3DCreate9(D3D_SDK_VERSION);
if (iface==NULL) {
logE("could not create Direct3D 9!");
return false;
}
priv=new FurnaceGUIRenderDX9Private;
SDL_GetWindowSize(win,&outW,&outH);
memset(&priv->present,0,sizeof(D3DPRESENT_PARAMETERS));
priv->present.Windowed=TRUE;
priv->present.SwapEffect=D3DSWAPEFFECT_DISCARD;
priv->present.BackBufferWidth=outW;
priv->present.BackBufferHeight=outH;
priv->present.BackBufferCount=1;
priv->present.BackBufferFormat=D3DFMT_UNKNOWN;
//priv->present.EnableAutoDepthStencil=TRUE;
//priv->present.AutoDepthStencilFormat=D3DFMT_D16;
if (swapInt>0) {
priv->present.PresentationInterval=D3DPRESENT_INTERVAL_ONE;
} else {
priv->present.PresentationInterval=D3DPRESENT_INTERVAL_IMMEDIATE;
}
priv->present.hDeviceWindow=window;
HRESULT result=iface->GetAdapterIdentifier(D3DADAPTER_DEFAULT,0,&adapterInfo);
if (result==D3D_OK) {
vendorName=fmt::sprintf("0x%.4X",adapterInfo.VendorId);
deviceName=fmt::sprintf("%s (%s)",adapterInfo.Description,adapterInfo.DeviceName);
apiVersion=fmt::sprintf("%.8X %.8X %s",adapterInfo.DriverVersion.HighPart,adapterInfo.DriverVersion.LowPart,adapterInfo.Driver);
} else {
logW("could not get adapter info! %.8x",result);
}
result=iface->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,window,D3DCREATE_HARDWARE_VERTEXPROCESSING,&priv->present,&device);
if (result!=D3D_OK) {
logW("no hardware vertex processing!");
result=iface->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,window,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&priv->present,&device);
if (result!=D3D_OK) {
logE("could not create device! %.8x",result);
iface->Release();
iface=NULL;
return false;
}
}
D3DCAPS9 caps;
result=device->GetDeviceCaps(&caps);
if (result==D3D_OK) {
supportsDynamicTex=(caps.Caps2&D3DCAPS2_DYNAMICTEXTURES);
squareTex=(caps.TextureCaps&D3DPTEXTURECAPS_SQUAREONLY);
supportsVSync=(caps.PresentationIntervals&D3DPRESENT_INTERVAL_ONE);
maxWidth=caps.MaxTextureWidth;
maxHeight=caps.MaxTextureHeight;
if (!supportsDynamicTex) {
logI("no support for dynamic textures");
}
if (squareTex) {
logI("square textures only");
}
}
result=device->CreateVertexBuffer(sizeof(WipeVertex)*4,0,D3DFVF_XYZ|D3DFVF_DIFFUSE,D3DPOOL_DEFAULT,&wipeBuf,NULL);
if (result!=D3D_OK) {
logE("could not create wipe buffer! %.8x",result);
}
return true;
}
void FurnaceGUIRenderDX9::initGUI(SDL_Window* win) {
ImGui_ImplSDL2_InitForD3D(win);
ImGui_ImplDX9_Init(device);
}
bool FurnaceGUIRenderDX9::quit() {
if (wipeBuf) {
wipeBuf->Release();
wipeBuf=NULL;
}
if (device) {
device->Release();
device=NULL;
}
if (iface) {
iface->Release();
iface=NULL;
}
priv->texPool.clear();
dead=false;
return true;
}
void FurnaceGUIRenderDX9::quitGUI() {
ImGui_ImplDX9_Shutdown();
}
bool FurnaceGUIRenderDX9::isDead() {
return dead;
}

101
src/gui/render/renderDX9.h Normal file
View file

@ -0,0 +1,101 @@
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2024 tildearrow and contributors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "../gui.h"
#ifdef INCLUDE_D3D9
#include <d3d9.h>
struct FurnaceGUIRenderDX9Private;
#else
typedef void IDirect3D9;
typedef void IDirect3DVertexBuffer9;
typedef void FurnaceGUIRenderDX9Private;
#endif
class FurnaceGUIRenderDX9: public FurnaceGUIRender {
IDirect3D9* iface;
IDirect3DDevice9* device;
FurnaceGUIRenderDX9Private* priv;
IDirect3DVertexBuffer9* wipeBuf;
int outW, outH, swapInterval;
bool dead, haveScene, supportsDynamicTex, supportsVSync, mustResize, squareTex, inScene;
// SHADERS //
int maxWidth, maxHeight;
String vendorName, deviceName, apiVersion;
public:
ImTextureID getTextureID(FurnaceGUITexture* which);
float getTextureU(FurnaceGUITexture* which);
float getTextureV(FurnaceGUITexture* which);
FurnaceGUITextureFormat getTextureFormat(FurnaceGUITexture* which);
bool isTextureValid(FurnaceGUITexture* which);
bool lockTexture(FurnaceGUITexture* which, void** data, int* pitch);
bool unlockTexture(FurnaceGUITexture* which);
bool updateTexture(FurnaceGUITexture* which, void* data, int pitch);
FurnaceGUITexture* createTexture(bool dynamic, int width, int height, bool interpolate=true, FurnaceGUITextureFormat format=GUI_TEXFORMAT_ABGR32);
bool destroyTexture(FurnaceGUITexture* which);
void setTextureBlendMode(FurnaceGUITexture* which, FurnaceGUIBlendMode mode);
void setBlendMode(FurnaceGUIBlendMode mode);
void resized(const SDL_Event& ev);
void clear(ImVec4 color);
bool newFrame();
bool canVSync();
void createFontsTexture();
void destroyFontsTexture();
void renderGUI();
void wipe(float alpha);
void present();
bool getOutputSize(int& w, int& h);
int getWindowFlags();
int getMaxTextureWidth();
int getMaxTextureHeight();
unsigned int getTextureFormats();
const char* getBackendName();
const char* getVendorName();
const char* getDeviceName();
const char* getAPIVersion();
void setSwapInterval(int swapInterval);
void preInit(const DivConfig& conf);
bool init(SDL_Window* win, int swapInterval);
void initGUI(SDL_Window* win);
void quitGUI();
bool quit();
bool isDead();
FurnaceGUIRenderDX9():
iface(NULL),
device(NULL),
priv(NULL),
wipeBuf(NULL),
outW(0),
outH(0),
swapInterval(1),
dead(false),
haveScene(false),
supportsDynamicTex(false),
supportsVSync(false),
mustResize(false),
squareTex(false),
inScene(false),
maxWidth(8192),
maxHeight(8192) {
}
};

View file

@ -65,11 +65,13 @@ class FurnaceGLTexture: public FurnaceGUITexture {
public:
GLuint id;
int width, height;
FurnaceGUITextureFormat format;
unsigned char* lockedData;
FurnaceGLTexture():
id(0),
width(0),
height(0),
format(GUI_TEXFORMAT_UNKNOWN),
lockedData(NULL) {}
};
@ -281,6 +283,11 @@ ImTextureID FurnaceGUIRenderGL::getTextureID(FurnaceGUITexture* which) {
return (ImTextureID)ret;
}
FurnaceGUITextureFormat FurnaceGUIRenderGL::getTextureFormat(FurnaceGUITexture* which) {
FurnaceGLTexture* t=(FurnaceGLTexture*)which;
return t->format;
}
bool FurnaceGUIRenderGL::lockTexture(FurnaceGUITexture* which, void** data, int* pitch) {
FurnaceGLTexture* t=(FurnaceGLTexture*)which;
if (t->lockedData!=NULL) return false;
@ -315,7 +322,11 @@ bool FurnaceGUIRenderGL::updateTexture(FurnaceGUITexture* which, void* data, int
return true;
}
FurnaceGUITexture* FurnaceGUIRenderGL::createTexture(bool dynamic, int width, int height, bool interpolate) {
FurnaceGUITexture* FurnaceGUIRenderGL::createTexture(bool dynamic, int width, int height, bool interpolate, FurnaceGUITextureFormat format) {
if (format!=GUI_TEXFORMAT_ABGR32) {
logE("unsupported texture format!");
return NULL;
}
FurnaceGLTexture* t=new FurnaceGLTexture;
C(glGenTextures(1,&t->id));
C(glBindTexture(GL_TEXTURE_2D,t->id));
@ -330,6 +341,7 @@ FurnaceGUITexture* FurnaceGUIRenderGL::createTexture(bool dynamic, int width, in
C(furActiveTexture(GL_TEXTURE0));
t->width=width;
t->height=height;
t->format=format;
return t;
}
@ -554,6 +566,10 @@ int FurnaceGUIRenderGL::getMaxTextureHeight() {
return maxHeight;
}
unsigned int FurnaceGUIRenderGL::getTextureFormats() {
return GUI_TEXFORMAT_ABGR32;
}
const char* FurnaceGUIRenderGL::getBackendName() {
return backendName.c_str();
}

View file

@ -56,10 +56,11 @@ class FurnaceGUIRenderGL: public FurnaceGUIRender {
public:
ImTextureID getTextureID(FurnaceGUITexture* which);
FurnaceGUITextureFormat getTextureFormat(FurnaceGUITexture* which);
bool lockTexture(FurnaceGUITexture* which, void** data, int* pitch);
bool unlockTexture(FurnaceGUITexture* which);
bool updateTexture(FurnaceGUITexture* which, void* data, int pitch);
FurnaceGUITexture* createTexture(bool dynamic, int width, int height, bool interpolate=true);
FurnaceGUITexture* createTexture(bool dynamic, int width, int height, bool interpolate=true, FurnaceGUITextureFormat format=GUI_TEXFORMAT_ABGR32);
bool destroyTexture(FurnaceGUITexture* which);
void setTextureBlendMode(FurnaceGUITexture* which, FurnaceGUIBlendMode mode);
void setBlendMode(FurnaceGUIBlendMode mode);
@ -77,6 +78,7 @@ class FurnaceGUIRenderGL: public FurnaceGUIRender {
int getWindowFlags();
int getMaxTextureWidth();
int getMaxTextureHeight();
unsigned int getTextureFormats();
const char* getBackendName();
const char* getVendorName();
const char* getDeviceName();

View file

@ -29,6 +29,7 @@ class FurnaceGL1Texture: public FurnaceGUITexture {
public:
GLuint id;
int width, height, widthReal, heightReal;
FurnaceGUITextureFormat format;
unsigned char* lockedData;
FurnaceGL1Texture():
id(0),
@ -36,6 +37,7 @@ class FurnaceGL1Texture: public FurnaceGUITexture {
height(0),
widthReal(0),
heightReal(0),
format(GUI_TEXFORMAT_UNKNOWN),
lockedData(NULL) {}
};
@ -46,14 +48,21 @@ ImTextureID FurnaceGUIRenderGL1::getTextureID(FurnaceGUITexture* which) {
float FurnaceGUIRenderGL1::getTextureU(FurnaceGUITexture* which) {
FurnaceGL1Texture* t=(FurnaceGL1Texture*)which;
if (t->widthReal<1) return 0.0f;
return (float)t->width/(float)t->widthReal;
}
float FurnaceGUIRenderGL1::getTextureV(FurnaceGUITexture* which) {
FurnaceGL1Texture* t=(FurnaceGL1Texture*)which;
if (t->heightReal<1) return 0.0f;
return (float)t->height/(float)t->heightReal;
}
FurnaceGUITextureFormat FurnaceGUIRenderGL1::getTextureFormat(FurnaceGUITexture* which) {
FurnaceGL1Texture* t=(FurnaceGL1Texture*)which;
return t->format;
}
bool FurnaceGUIRenderGL1::lockTexture(FurnaceGUITexture* which, void** data, int* pitch) {
FurnaceGL1Texture* t=(FurnaceGL1Texture*)which;
if (t->lockedData!=NULL) return false;
@ -90,7 +99,11 @@ bool FurnaceGUIRenderGL1::updateTexture(FurnaceGUITexture* which, void* data, in
return true;
}
FurnaceGUITexture* FurnaceGUIRenderGL1::createTexture(bool dynamic, int width, int height, bool interpolate) {
FurnaceGUITexture* FurnaceGUIRenderGL1::createTexture(bool dynamic, int width, int height, bool interpolate, FurnaceGUITextureFormat format) {
if (format!=GUI_TEXFORMAT_ABGR32) {
logE("unsupported texture format!");
return NULL;
}
FurnaceGL1Texture* t=new FurnaceGL1Texture;
C(glGenTextures(1,&t->id));
C(glBindTexture(GL_TEXTURE_2D,t->id));
@ -119,6 +132,7 @@ FurnaceGUITexture* FurnaceGUIRenderGL1::createTexture(bool dynamic, int width, i
t->height=height;
t->widthReal=widthReal;
t->heightReal=heightReal;
t->format=format;
return t;
}
@ -219,6 +233,10 @@ int FurnaceGUIRenderGL1::getMaxTextureHeight() {
return maxHeight;
}
unsigned int FurnaceGUIRenderGL1::getTextureFormats() {
return GUI_TEXFORMAT_ABGR32;
}
const char* FurnaceGUIRenderGL1::getBackendName() {
return "OpenGL 1.1";
}

View file

@ -32,10 +32,11 @@ class FurnaceGUIRenderGL1: public FurnaceGUIRender {
ImTextureID getTextureID(FurnaceGUITexture* which);
float getTextureU(FurnaceGUITexture* which);
float getTextureV(FurnaceGUITexture* which);
FurnaceGUITextureFormat getTextureFormat(FurnaceGUITexture* which);
bool lockTexture(FurnaceGUITexture* which, void** data, int* pitch);
bool unlockTexture(FurnaceGUITexture* which);
bool updateTexture(FurnaceGUITexture* which, void* data, int pitch);
FurnaceGUITexture* createTexture(bool dynamic, int width, int height, bool interpolate=true);
FurnaceGUITexture* createTexture(bool dynamic, int width, int height, bool interpolate=true, FurnaceGUITextureFormat format=GUI_TEXFORMAT_ABGR32);
bool destroyTexture(FurnaceGUITexture* which);
void setTextureBlendMode(FurnaceGUITexture* which, FurnaceGUIBlendMode mode);
void setBlendMode(FurnaceGUIBlendMode mode);
@ -51,6 +52,7 @@ class FurnaceGUIRenderGL1: public FurnaceGUIRender {
int getWindowFlags();
int getMaxTextureWidth();
int getMaxTextureHeight();
unsigned int getTextureFormats();
const char* getBackendName();
const char* getVendorName();
const char* getDeviceName();

View file

@ -28,10 +28,11 @@ class FurnaceGUIRenderMetal: public FurnaceGUIRender {
String vendorName, deviceName, apiVersion;
public:
ImTextureID getTextureID(FurnaceGUITexture* which);
FurnaceGUITextureFormat getTextureFormat(FurnaceGUITexture* which);
bool lockTexture(FurnaceGUITexture* which, void** data, int* pitch);
bool unlockTexture(FurnaceGUITexture* which);
bool updateTexture(FurnaceGUITexture* which, void* data, int pitch);
FurnaceGUITexture* createTexture(bool dynamic, int width, int height, bool interpolate=true);
FurnaceGUITexture* createTexture(bool dynamic, int width, int height, bool interpolate=true, FurnaceGUITextureFormat format=GUI_TEXFORMAT_ABGR32);
bool destroyTexture(FurnaceGUITexture* which);
void setTextureBlendMode(FurnaceGUITexture* which, FurnaceGUIBlendMode mode);
void setBlendMode(FurnaceGUIBlendMode mode);
@ -47,6 +48,7 @@ class FurnaceGUIRenderMetal: public FurnaceGUIRender {
int getWindowFlags();
int getMaxTextureWidth();
int getMaxTextureHeight();
unsigned int getTextureFormats();
const char* getBackendName();
const char* getVendorName();
const char* getDeviceName();

View file

@ -44,11 +44,13 @@ class FurnaceMetalTexture: public FurnaceGUITexture {
public:
id<MTLTexture> tex;
int width, height;
FurnaceGUITextureFormat format;
unsigned char* lockedData;
FurnaceMetalTexture():
tex(NULL),
width(0),
height(0),
format(GUI_TEXFORMAT_UNKNOWN),
lockedData(NULL) {}
};
@ -57,6 +59,11 @@ ImTextureID FurnaceGUIRenderMetal::getTextureID(FurnaceGUITexture* which) {
return t->tex;
}
FurnaceGUITextureFormat FurnaceGUIRenderMetal::getTextureFormat(FurnaceGUITexture* which) {
FurnaceMetalTexture* t=(FurnaceMetalTexture*)which;
return t->format;
}
bool FurnaceGUIRenderMetal::lockTexture(FurnaceGUITexture* which, void** data, int* pitch) {
FurnaceMetalTexture* t=(FurnaceMetalTexture*)which;
if (t->lockedData!=NULL) return false;
@ -84,7 +91,11 @@ bool FurnaceGUIRenderMetal::updateTexture(FurnaceGUITexture* which, void* data,
return true;
}
FurnaceGUITexture* FurnaceGUIRenderMetal::createTexture(bool dynamic, int width, int height, bool interpolate) {
FurnaceGUITexture* FurnaceGUIRenderMetal::createTexture(bool dynamic, int width, int height, bool interpolate, FurnaceGUITextureFormat format) {
if (format!=GUI_TEXFORMAT_ABGR32) {
logE("unsupported texture format!");
return NULL;
}
MTLTextureDescriptor* texDesc=[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm width:(NSUInteger)width height:(NSUInteger)height mipmapped:NO];
texDesc.usage=MTLTextureUsageShaderRead;
texDesc.storageMode=MTLStorageModeManaged;
@ -193,6 +204,10 @@ int FurnaceGUIRenderMetal::getMaxTextureHeight() {
return bigTextures?16384:8192;
}
unsigned int FurnaceGUIRenderMetal::getTextureFormats() {
return GUI_TEXFORMAT_ABGR32;
}
const char* FurnaceGUIRenderMetal::getBackendName() {
return "Metal";
}

View file

@ -24,8 +24,10 @@
class FurnaceSDLTexture: public FurnaceGUITexture {
public:
SDL_Texture* tex;
FurnaceGUITextureFormat format;
FurnaceSDLTexture():
tex(NULL) {}
tex(NULL),
format(GUI_TEXFORMAT_UNKNOWN) {}
};
ImTextureID FurnaceGUIRenderSDL::getTextureID(FurnaceGUITexture* which) {
@ -33,6 +35,11 @@ ImTextureID FurnaceGUIRenderSDL::getTextureID(FurnaceGUITexture* which) {
return t->tex;
}
FurnaceGUITextureFormat FurnaceGUIRenderSDL::getTextureFormat(FurnaceGUITexture* which) {
FurnaceSDLTexture* t=(FurnaceSDLTexture*)which;
return t->format;
}
bool FurnaceGUIRenderSDL::lockTexture(FurnaceGUITexture* which, void** data, int* pitch) {
FurnaceSDLTexture* t=(FurnaceSDLTexture*)which;
return SDL_LockTexture(t->tex,NULL,data,pitch)==0;
@ -49,7 +56,11 @@ bool FurnaceGUIRenderSDL::updateTexture(FurnaceGUITexture* which, void* data, in
return SDL_UpdateTexture(t->tex,NULL,data,pitch)==0;
}
FurnaceGUITexture* FurnaceGUIRenderSDL::createTexture(bool dynamic, int width, int height, bool interpolate) {
FurnaceGUITexture* FurnaceGUIRenderSDL::createTexture(bool dynamic, int width, int height, bool interpolate, FurnaceGUITextureFormat format) {
if (format!=GUI_TEXFORMAT_ABGR32) {
logE("unsupported texture format!");
return NULL;
}
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY,interpolate?"1":"0");
SDL_Texture* t=SDL_CreateTexture(sdlRend,SDL_PIXELFORMAT_ABGR8888,dynamic?SDL_TEXTUREACCESS_STREAMING:SDL_TEXTUREACCESS_STATIC,width,height);
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY,"1");
@ -57,6 +68,7 @@ FurnaceGUITexture* FurnaceGUIRenderSDL::createTexture(bool dynamic, int width, i
if (t==NULL) return NULL;
FurnaceSDLTexture* ret=new FurnaceSDLTexture;
ret->tex=t;
ret->format=format;
return ret;
}
@ -156,6 +168,10 @@ int FurnaceGUIRenderSDL::getMaxTextureHeight() {
return renderInfo.max_texture_height;
}
unsigned int FurnaceGUIRenderSDL::getTextureFormats() {
return GUI_TEXFORMAT_ABGR32;
}
const char* FurnaceGUIRenderSDL::getBackendName() {
return "SDL Renderer";
}

View file

@ -26,10 +26,11 @@ class FurnaceGUIRenderSDL: public FurnaceGUIRender {
bool swapIntervalSet;
public:
ImTextureID getTextureID(FurnaceGUITexture* which);
FurnaceGUITextureFormat getTextureFormat(FurnaceGUITexture* which);
bool lockTexture(FurnaceGUITexture* which, void** data, int* pitch);
bool unlockTexture(FurnaceGUITexture* which);
bool updateTexture(FurnaceGUITexture* which, void* data, int pitch);
FurnaceGUITexture* createTexture(bool dynamic, int width, int height, bool interpolate=true);
FurnaceGUITexture* createTexture(bool dynamic, int width, int height, bool interpolate=true, FurnaceGUITextureFormat format=GUI_TEXFORMAT_ABGR32);
bool destroyTexture(FurnaceGUITexture* which);
void setTextureBlendMode(FurnaceGUITexture* which, FurnaceGUIBlendMode mode);
void setBlendMode(FurnaceGUIBlendMode mode);
@ -45,6 +46,7 @@ class FurnaceGUIRenderSDL: public FurnaceGUIRender {
int getWindowFlags();
int getMaxTextureWidth();
int getMaxTextureHeight();
unsigned int getTextureFormats();
const char* getBackendName();
const char* getVendorName();
const char* getDeviceName();

View file

@ -24,8 +24,10 @@
class FurnaceSoftwareTexture: public FurnaceGUITexture {
public:
SWTexture* tex;
FurnaceGUITextureFormat format;
FurnaceSoftwareTexture():
tex(NULL) {}
tex(NULL),
format(GUI_TEXFORMAT_UNKNOWN) {}
};
ImTextureID FurnaceGUIRenderSoftware::getTextureID(FurnaceGUITexture* which) {
@ -33,6 +35,11 @@ ImTextureID FurnaceGUIRenderSoftware::getTextureID(FurnaceGUITexture* which) {
return t->tex;
}
FurnaceGUITextureFormat FurnaceGUIRenderSoftware::getTextureFormat(FurnaceGUITexture* which) {
FurnaceSoftwareTexture* t=(FurnaceSoftwareTexture*)which;
return t->format;
}
bool FurnaceGUIRenderSoftware::lockTexture(FurnaceGUITexture* which, void** data, int* pitch) {
FurnaceSoftwareTexture* t=(FurnaceSoftwareTexture*)which;
if (!t->tex->managed) return false;
@ -52,9 +59,14 @@ bool FurnaceGUIRenderSoftware::updateTexture(FurnaceGUITexture* which, void* dat
return true;
}
FurnaceGUITexture* FurnaceGUIRenderSoftware::createTexture(bool dynamic, int width, int height, bool interpolate) {
FurnaceGUITexture* FurnaceGUIRenderSoftware::createTexture(bool dynamic, int width, int height, bool interpolate, FurnaceGUITextureFormat format) {
if (format!=GUI_TEXFORMAT_ARGB32) {
logE("unsupported texture format!");
return NULL;
}
FurnaceSoftwareTexture* ret=new FurnaceSoftwareTexture;
ret->tex=new SWTexture(width,height);
ret->format=format;
return ret;
}
@ -141,6 +153,10 @@ int FurnaceGUIRenderSoftware::getMaxTextureHeight() {
return 16384;
}
unsigned int FurnaceGUIRenderSoftware::getTextureFormats() {
return GUI_TEXFORMAT_ARGB32;
}
const char* FurnaceGUIRenderSoftware::getBackendName() {
return "Software";
}

View file

@ -23,10 +23,11 @@ class FurnaceGUIRenderSoftware: public FurnaceGUIRender {
SDL_Window* sdlWin;
public:
ImTextureID getTextureID(FurnaceGUITexture* which);
FurnaceGUITextureFormat getTextureFormat(FurnaceGUITexture* which);
bool lockTexture(FurnaceGUITexture* which, void** data, int* pitch);
bool unlockTexture(FurnaceGUITexture* which);
bool updateTexture(FurnaceGUITexture* which, void* data, int pitch);
FurnaceGUITexture* createTexture(bool dynamic, int width, int height, bool interpolate=true);
FurnaceGUITexture* createTexture(bool dynamic, int width, int height, bool interpolate=true, FurnaceGUITextureFormat format=GUI_TEXFORMAT_ABGR32);
bool destroyTexture(FurnaceGUITexture* which);
void setTextureBlendMode(FurnaceGUITexture* which, FurnaceGUIBlendMode mode);
void setBlendMode(FurnaceGUIBlendMode mode);
@ -42,6 +43,7 @@ class FurnaceGUIRenderSoftware: public FurnaceGUIRender {
int getWindowFlags();
int getMaxTextureWidth();
int getMaxTextureHeight();
unsigned int getTextureFormats();
const char* getBackendName();
const char* getVendorName();
const char* getDeviceName();

View file

@ -31,6 +31,15 @@
#include "sampleUtil.h"
#include "util.h"
#define SWAP_COLOR_ARGB(x) \
x=(x&0xff00ff00)|((x&0xff)<<16)|((x&0xff0000)>>16);
#define SWAP_COLOR_BGRA(x) \
x=((x&0xff0000000)>>24)|((x&0xffffff)<<8);
#define SWAP_COLOR_RGBA(x) \
x=((x&0xff)<<24)|((x&0xff00)<<8)|((x&0xff0000)>>8)|((x&0xff000000)>>24);
const double timeDivisors[10]={
1000.0, 500.0, 200.0, 100.0, 50.0, 20.0, 10.0, 5.0, 2.0, 1.0
};
@ -1469,14 +1478,14 @@ void FurnaceGUI::drawSampleEdit() {
}
}
if (sampleTex==NULL || sampleTexW!=avail.x || sampleTexH!=avail.y) {
if (sampleTex==NULL || sampleTexW!=avail.x || sampleTexH!=avail.y || !rend->isTextureValid(sampleTex)) {
if (sampleTex!=NULL) {
rend->destroyTexture(sampleTex);
sampleTex=NULL;
}
if (avail.x>=1 && avail.y>=1) {
logD("recreating sample texture.");
sampleTex=rend->createTexture(true,avail.x,avail.y);
sampleTex=rend->createTexture(true,avail.x,avail.y,true,bestTexFormat);
sampleTexW=avail.x;
sampleTexH=avail.y;
if (sampleTex==NULL) {
@ -1501,6 +1510,30 @@ void FurnaceGUI::drawSampleEdit() {
ImU32 bgColorLoop=ImGui::GetColorU32(uiColors[GUI_COLOR_SAMPLE_LOOP]);
ImU32 lineColor=ImGui::GetColorU32(uiColors[GUI_COLOR_SAMPLE_FG]);
ImU32 centerLineColor=ImGui::GetColorU32(uiColors[GUI_COLOR_SAMPLE_CENTER]);
switch (rend->getTextureFormat(sampleTex)) {
case GUI_TEXFORMAT_ARGB32:
SWAP_COLOR_ARGB(bgColor);
SWAP_COLOR_ARGB(bgColorLoop);
SWAP_COLOR_ARGB(lineColor);
SWAP_COLOR_ARGB(centerLineColor);
break;
case GUI_TEXFORMAT_BGRA32:
SWAP_COLOR_BGRA(bgColor);
SWAP_COLOR_BGRA(bgColorLoop);
SWAP_COLOR_BGRA(lineColor);
SWAP_COLOR_BGRA(centerLineColor);
break;
case GUI_TEXFORMAT_RGBA32:
SWAP_COLOR_RGBA(bgColor);
SWAP_COLOR_RGBA(bgColorLoop);
SWAP_COLOR_RGBA(lineColor);
SWAP_COLOR_RGBA(centerLineColor);
break;
default:
break;
}
int ij=0;
for (int i=0; i<availY; i++) {
for (int j=0; j<availX; j++) {

View file

@ -388,6 +388,12 @@ void FurnaceGUI::drawSettings() {
settingsChanged=true;
}
#endif
#ifdef HAVE_RENDER_DX9
if (ImGui::Selectable("DirectX 9",curRenderBackend=="DirectX 9")) {
settings.renderBackend="DirectX 9";
settingsChanged=true;
}
#endif
#ifdef HAVE_RENDER_METAL
if (ImGui::Selectable("Metal",curRenderBackend=="Metal")) {
settings.renderBackend="Metal";

View file

@ -791,7 +791,10 @@ void FurnaceGUI::drawTutorial() {
cv->hiScore=cvHiScore;
}
if (cvTex==NULL) {
cvTex=rend->createTexture(true,320,224,false);
cvTex=rend->createTexture(true,320,224,false,bestTexFormat);
} else if (!rend->isTextureValid(cvTex)) {
rend->destroyTexture(cvTex);
cvTex=rend->createTexture(true,320,224,false,bestTexFormat);
}
if (cv->pleaseInitSongs) {