mirror of https://github.com/PCSX2/pcsx2.git
gsdx: merge the opengl branch to ease futur development and allow GSdx by default on linux
* for the moment only the SW render is supported, hopefully HW will come some day. And linux only for the moment. * Require an OpenGL3 GPU (==Dx10) ie Nvidia >= 8800, AMD >= HD2000) * Require an OpenGL4.2 compatible drivers => no opensource driver supported neither Intel driver. * Build by default without SDL support which will dropped later. You need to add this define "ENABLE_SDL_DEV" on Win. git-svn-id: http://pcsx2.googlecode.com/svn/trunk@5186 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
commit
46838ca4ee
|
@ -410,6 +410,9 @@ X11_GL_CreateContext(_THIS, SDL_Window * window)
|
|||
_this->gl_config.major_version,
|
||||
GLX_CONTEXT_MINOR_VERSION_ARB,
|
||||
_this->gl_config.minor_version,
|
||||
//FIXME GREGORY
|
||||
// Request a debug context to ease opengl development
|
||||
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB,
|
||||
0
|
||||
};
|
||||
|
||||
|
|
49
build.sh
49
build.sh
|
@ -18,23 +18,38 @@ flags=""
|
|||
args="$@"
|
||||
clean_build=false
|
||||
|
||||
for f in $args; do
|
||||
if [ "$f" = "gsdx" ] ; then
|
||||
flags="$flags -DFORCE_INTERNAL_SDL=TRUE"
|
||||
fi
|
||||
if [ "$f" = "dev" ] ; then
|
||||
flags="$flags -DCMAKE_BUILD_TYPE=Devel"
|
||||
fi
|
||||
if [ "$f" = "debug" ] ; then
|
||||
flags="$flags -DCMAKE_BUILD_TYPE=Debug"
|
||||
fi
|
||||
if [ "$f" = "release" ] ; then
|
||||
flags="$flags -DCMAKE_BUILD_TYPE=Release"
|
||||
fi
|
||||
if [ "$f" = "clean" ] ; then
|
||||
clean_build=true
|
||||
fi
|
||||
done
|
||||
for f in $*
|
||||
do
|
||||
case $f in
|
||||
--sdl13)
|
||||
flags="$flags -DFORCE_INTERNAL_SDL=TRUE"
|
||||
;;
|
||||
--dev)
|
||||
flags="$flags -DCMAKE_BUILD_TYPE=Devel"
|
||||
;;
|
||||
--devel)
|
||||
flags="$flags -DCMAKE_BUILD_TYPE=Devel"
|
||||
;;
|
||||
--debug)
|
||||
flags="$flags -DCMAKE_BUILD_TYPE=Debug"
|
||||
;;
|
||||
--release)
|
||||
flags="$flags -DCMAKE_BUILD_TYPE=Release"
|
||||
;;
|
||||
--clean)
|
||||
clean_build=true
|
||||
;;
|
||||
*)
|
||||
# unknown option
|
||||
echo "Valid options are:"
|
||||
echo "--dev / --devel - Build pcsx2 as a Development build."
|
||||
echo "--debug - Build pcsx2 as a Debug build."
|
||||
echo "--release - Build pcsx2 as a Release build."
|
||||
echo "--clean - Do a clean build."
|
||||
echo "--sdl13 - Use the internal copy of sdl (needed for gsdx to use sdl)."
|
||||
exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
rm install_log.txt
|
||||
|
||||
|
|
|
@ -125,13 +125,13 @@ endif(GTK2_FOUND)
|
|||
# -X11
|
||||
# -PCSX2 SDL
|
||||
#---------------------------------------
|
||||
if(OPENGL_FOUND AND X11_FOUND AND projectSDL)
|
||||
if(OPENGL_FOUND AND X11_FOUND)
|
||||
set(GSdx TRUE)
|
||||
else(OPENGL_FOUND AND X11_FOUND AND projectSDL)
|
||||
else(OPENGL_FOUND AND X11_FOUND)
|
||||
set(GSdx FALSE)
|
||||
message(STATUS "Skip build of GSdx: miss some dependencies")
|
||||
message(STATUS "${msg_dep_gsdx}")
|
||||
endif(OPENGL_FOUND AND X11_FOUND AND projectSDL)
|
||||
endif(OPENGL_FOUND AND X11_FOUND)
|
||||
#---------------------------------------
|
||||
|
||||
#---------------------------------------
|
||||
|
|
|
@ -18,6 +18,9 @@ set(CommonFlags
|
|||
-Wunused-variable
|
||||
-std=c++0x
|
||||
-fno-strict-aliasing
|
||||
-DOGL_DEBUG # FIXME remove me when code is ready
|
||||
# Unload of Geometry shader was fixed in Cat 12.3 (ie OpenGL version string: 4.2.11554)
|
||||
#-DAMD_DRIVER_WORKAROUND
|
||||
)
|
||||
|
||||
set(OptimizationFlags
|
||||
|
@ -25,22 +28,25 @@ set(OptimizationFlags
|
|||
-DNDEBUG
|
||||
)
|
||||
|
||||
if(projectSDL)
|
||||
set(SDLFlags -DENABLE_SDL_DEV)
|
||||
else(projectSDL)
|
||||
set(SDLFlags "")
|
||||
endif(projectSDL)
|
||||
|
||||
# Debug - Build
|
||||
if(CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||
# add defines
|
||||
add_definitions(${CommonFlags} -g -Wall)
|
||||
add_definitions(${CommonFlags} ${SDLFlags} -DOGL_DEBUG -g -Wall)
|
||||
endif(CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||
|
||||
# Devel - Build
|
||||
if(CMAKE_BUILD_TYPE STREQUAL Devel)
|
||||
# add defines
|
||||
add_definitions(${CommonFlags} ${OptimizationFlags} -g -W)
|
||||
add_definitions(${CommonFlags} ${SDLFlags} ${OptimizationFlags} -g -W)
|
||||
endif(CMAKE_BUILD_TYPE STREQUAL Devel)
|
||||
|
||||
# Release - Build
|
||||
if(CMAKE_BUILD_TYPE STREQUAL Release)
|
||||
# add defines
|
||||
add_definitions(${CommonFlags} ${OptimizationFlags} -W)
|
||||
add_definitions(${CommonFlags} ${SDLFlags} ${OptimizationFlags} -W)
|
||||
endif(CMAKE_BUILD_TYPE STREQUAL Release)
|
||||
|
||||
set(GSdxSources
|
||||
|
@ -60,6 +66,7 @@ set(GSdxSources
|
|||
GSCodeBuffer.cpp
|
||||
GSCrc.cpp
|
||||
GSDevice.cpp
|
||||
GSDeviceOGL.cpp
|
||||
GSDeviceSDL.cpp
|
||||
GSDeviceSW.cpp
|
||||
GSDeviceNull.cpp
|
||||
|
@ -77,7 +84,9 @@ set(GSdxSources
|
|||
GSPerfMon.cpp
|
||||
GSRasterizer.cpp
|
||||
GSRenderer.cpp
|
||||
GSRendererHW.cpp
|
||||
GSRendererNull.cpp
|
||||
GSRendererOGL.cpp
|
||||
GSRendererSW.cpp
|
||||
GSSetting.cpp
|
||||
GSSetupPrimCodeGenerator.cpp
|
||||
|
@ -90,6 +99,9 @@ set(GSdxSources
|
|||
GSTexture.cpp
|
||||
GSTextureCache.cpp
|
||||
GSTextureCacheSW.cpp
|
||||
GSTextureCacheOGL.cpp
|
||||
GSTextureFXOGL.cpp
|
||||
GSTextureOGL.cpp
|
||||
GSTextureNull.cpp
|
||||
GSTextureSW.cpp
|
||||
GSThread.cpp
|
||||
|
@ -121,6 +133,7 @@ set(GSdxHeaders
|
|||
GSCodeBuffer.h
|
||||
GSCrc.h
|
||||
GSDevice.h
|
||||
GSDeviceOGL.h
|
||||
GSDeviceNull.h
|
||||
GSDirtyRect.h
|
||||
GSDrawScanline.h
|
||||
|
@ -129,12 +142,15 @@ set(GSdxHeaders
|
|||
GSDrawingEnvironment.h
|
||||
GSDump.h
|
||||
GSFunctionMap.h
|
||||
GSLinuxLogo.h
|
||||
GSLocalMemory.h
|
||||
GSPerfMon.h
|
||||
GSRasterizer.h
|
||||
GSRenderer.h
|
||||
GSRendererNull.h
|
||||
GSRendererSW.h
|
||||
GSRendererHW.h
|
||||
GSRendererOGL.h
|
||||
GSScanlineEnvironment.h
|
||||
GSSetting.h
|
||||
GSSetupPrimCodeGenerator.h
|
||||
|
@ -143,6 +159,7 @@ set(GSdxHeaders
|
|||
GSTexture.h
|
||||
GSTextureCache.h
|
||||
GSTextureCacheSW.h
|
||||
GSTextureCacheOGL.h
|
||||
GSTextureNull.h
|
||||
GSThread.h
|
||||
GSUtil.h
|
||||
|
@ -161,33 +178,76 @@ set(GSdxHeaders
|
|||
xbyak/xbyak_util.h
|
||||
)
|
||||
|
||||
# add additional include directories
|
||||
include_directories(.)
|
||||
|
||||
# add library
|
||||
add_library(${Output} SHARED
|
||||
${GSdxSources}
|
||||
${GSdxHeaders}
|
||||
)
|
||||
add_library(${Output} SHARED ${GSdxSources} ${GSdxHeaders})
|
||||
|
||||
# link target with X11
|
||||
target_link_libraries(${Output} ${X11_LIBRARIES})
|
||||
|
||||
# link target with SDL
|
||||
target_link_libraries(${Output} ${SDL_LIBRARY})
|
||||
target_link_libraries(${Output} ${GLEW_LIBRARY})
|
||||
target_link_libraries(${Output} ${OPENGL_LIBRARIES})
|
||||
if(projectSDL)
|
||||
target_link_libraries(${Output} ${SDL_LIBRARY})
|
||||
endif(projectSDL)
|
||||
|
||||
if(Linux)
|
||||
# link target with gtk2
|
||||
target_link_libraries(${Output} ${GTK2_LIBRARIES})
|
||||
endif(Linux)
|
||||
|
||||
# User flags options
|
||||
if(NOT USER_CMAKE_LD_FLAGS STREQUAL "")
|
||||
target_link_libraries(${Output} "${USER_CMAKE_LD_FLAGS}")
|
||||
endif(NOT USER_CMAKE_LD_FLAGS STREQUAL "")
|
||||
|
||||
if(PACKAGE_MODE)
|
||||
install(TARGETS ${Output} DESTINATION ${PLUGIN_DIR})
|
||||
|
||||
foreach(glsl IN ITEMS convert.glsl interlace.glsl merge.glsl tfx.glsl shadeboost.glsl)
|
||||
install(FILES ${PROJECT_SOURCE_DIR}/plugins/GSdx/res/${glsl} DESTINATION ${PLUGIN_DIR})
|
||||
endforeach(glsl IN ITEMS convert.glsl interlace.glsl merge.glsl tfx.glsl shadeboost.glsl)
|
||||
else(PACKAGE_MODE)
|
||||
install(TARGETS ${Output} DESTINATION ${CMAKE_SOURCE_DIR}/bin/plugins)
|
||||
|
||||
foreach(glsl IN ITEMS convert.glsl interlace.glsl merge.glsl tfx.glsl shadeboost.glsl)
|
||||
install(FILES ${PROJECT_SOURCE_DIR}/plugins/GSdx/res/${glsl} DESTINATION ${CMAKE_SOURCE_DIR}/bin/plugins)
|
||||
endforeach(glsl IN ITEMS convert.glsl interlace.glsl merge.glsl tfx.glsl shadeboost.glsl)
|
||||
endif(PACKAGE_MODE)
|
||||
|
||||
################################### Replay Loader
|
||||
set(Replay pcsx2_GSReplayLoader)
|
||||
set(Static GSdx-static)
|
||||
|
||||
# We can have separate option for gsdx inside the player. It will only
|
||||
# cost a 2nd rebuild of gsdx...
|
||||
#add_definitions(${CommonFlags} ${SDLFlags} ${OptimizationFlags} -W)
|
||||
|
||||
add_library(${Static} STATIC ${GSdxSources} ${GSdxHeaders})
|
||||
|
||||
add_executable(${Replay} linux_replay.cpp)
|
||||
|
||||
target_link_libraries(${Static} ${OPENGL_LIBRARIES})
|
||||
target_link_libraries(${Static} ${X11_LIBRARIES})
|
||||
target_link_libraries(${Static} ${GLEW_LIBRARY})
|
||||
target_link_libraries(${Static} ${GTK2_LIBRARIES})
|
||||
if(projectSDL)
|
||||
target_link_libraries(${Static} ${SDL_LIBRARY})
|
||||
endif(projectSDL)
|
||||
|
||||
target_link_libraries(${Replay} ${Static})
|
||||
# Warning others lib must be linked after GSdx...
|
||||
target_link_libraries(${Replay} ${OPENGL_LIBRARIES})
|
||||
target_link_libraries(${Replay} ${X11_LIBRARIES})
|
||||
target_link_libraries(${Replay} ${GLEW_LIBRARY})
|
||||
target_link_libraries(${Replay} ${GTK2_LIBRARIES})
|
||||
if(projectSDL)
|
||||
target_link_libraries(${Replay} ${SDL_LIBRARY})
|
||||
endif(projectSDL)
|
||||
|
||||
|
||||
if(NOT USER_CMAKE_LD_FLAGS STREQUAL "")
|
||||
target_link_libraries(${Replay} "${USER_CMAKE_LD_FLAGS}")
|
||||
endif(NOT USER_CMAKE_LD_FLAGS STREQUAL "")
|
||||
|
||||
if(PACKAGE_MODE)
|
||||
install(TARGETS ${Replay} DESTINATION bin)
|
||||
else(PACKAGE_MODE)
|
||||
install(TARGETS ${Replay} DESTINATION ${CMAKE_SOURCE_DIR}/bin)
|
||||
endif(PACKAGE_MODE)
|
||||
|
|
|
@ -118,7 +118,9 @@ EXPORT_C_(int32) GPUopen(void* hWnd)
|
|||
case 0: s_gpu = new GPURendererSW(new GSDevice9(), threads); break;
|
||||
case 1: s_gpu = new GPURendererSW(new GSDevice11(), threads); break;
|
||||
#endif
|
||||
#ifdef ENABLE_SDL_DEV
|
||||
case 2: s_gpu = new GPURendererSW(new GSDeviceSDL(), threads); break;
|
||||
#endif
|
||||
case 3: s_gpu = new GPURendererSW(new GSDeviceNull(), threads); break;
|
||||
//case 4: s_gpu = new GPURendererNull(new GSDeviceNull()); break;
|
||||
}
|
||||
|
|
|
@ -40,6 +40,9 @@ static HRESULT s_hr = E_FAIL;
|
|||
|
||||
#else
|
||||
|
||||
#include "GSDeviceOGL.h"
|
||||
#include "GSRendererOGL.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkx.h>
|
||||
|
||||
|
@ -134,6 +137,7 @@ EXPORT_C_(int) GSinit()
|
|||
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SDL_DEV
|
||||
if(!SDL_WasInit(SDL_INIT_VIDEO))
|
||||
{
|
||||
if(SDL_Init(SDL_INIT_VIDEO) < 0)
|
||||
|
@ -141,6 +145,7 @@ EXPORT_C_(int) GSinit()
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -153,7 +158,9 @@ EXPORT_C GSshutdown()
|
|||
|
||||
s_renderer = -1;
|
||||
|
||||
#ifdef ENABLE_SDL_DEV
|
||||
SDL_Quit();
|
||||
#endif
|
||||
|
||||
#ifdef _WINDOWS
|
||||
|
||||
|
@ -231,12 +238,15 @@ static int _GSopen(void** dsp, char* title, int renderer, int threads = -1)
|
|||
switch(renderer / 3)
|
||||
{
|
||||
default:
|
||||
#ifdef _WINDOWS
|
||||
case 0: dev = new GSDevice9(); break;
|
||||
case 1: dev = new GSDevice11(); break;
|
||||
#endif
|
||||
case 2: dev = new GSDeviceSDL(); break;
|
||||
case 3: dev = new GSDeviceNull(); break;
|
||||
#ifdef _WINDOWS
|
||||
case 0: dev = new GSDevice9(); break;
|
||||
case 1: dev = new GSDevice11(); break;
|
||||
#endif
|
||||
#ifdef ENABLE_SDL_DEV
|
||||
case 2: dev = new GSDeviceSDL(); break;
|
||||
#endif
|
||||
case 3: dev = new GSDeviceNull(); break;
|
||||
case 4: dev = new GSDeviceOGL(); break;
|
||||
}
|
||||
|
||||
if(dev == NULL)
|
||||
|
@ -249,11 +259,13 @@ static int _GSopen(void** dsp, char* title, int renderer, int threads = -1)
|
|||
switch(renderer % 3)
|
||||
{
|
||||
default:
|
||||
#ifdef _WINDOWS
|
||||
case 0:
|
||||
#ifdef _WINDOWS
|
||||
s_gs = (renderer / 3) == 0 ? (GSRenderer*)new GSRendererDX9() : (GSRenderer*)new GSRendererDX11();
|
||||
#else
|
||||
s_gs = (GSRenderer*)new GSRendererOGL();
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
case 1:
|
||||
s_gs = new GSRendererSW(threads);
|
||||
break;
|
||||
|
@ -304,9 +316,10 @@ static int _GSopen(void** dsp, char* title, int renderer, int threads = -1)
|
|||
{
|
||||
s_gs->SetMultithreaded(true);
|
||||
|
||||
#ifdef __LINUX__
|
||||
#ifdef _LINUX
|
||||
// Get the Xwindow from dsp.
|
||||
s_gs->m_wnd.Attach((void*)((uint32*)(dsp)+1), false);
|
||||
if( !s_gs->m_wnd.Attach((void*)((uint32*)(dsp)+1), false) )
|
||||
return -1;
|
||||
#else
|
||||
s_gs->m_wnd.Attach(*dsp, false);
|
||||
#endif
|
||||
|
@ -350,7 +363,8 @@ EXPORT_C_(int) GSopen2(void** dsp, uint32 flags)
|
|||
|
||||
int retval = _GSopen(dsp, NULL, renderer);
|
||||
|
||||
s_gs->SetAspectRatio(0); // PCSX2 manages the aspect ratios
|
||||
if (s_gs != NULL)
|
||||
s_gs->SetAspectRatio(0); // PCSX2 manages the aspect ratios
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -421,12 +435,41 @@ EXPORT_C GSwriteCSR(uint32 csr)
|
|||
|
||||
EXPORT_C GSreadFIFO(uint8* mem)
|
||||
{
|
||||
#ifdef _LINUX
|
||||
// FIXME: double check which thread call this function
|
||||
// See fifo2 issue below
|
||||
if (theApp.GetConfig("renderer", 0) / 3 == 4) {
|
||||
fprintf(stderr, "Disable FIFO1 on opengl\n");
|
||||
}
|
||||
s_gs->m_wnd.AttachContext();
|
||||
#endif
|
||||
|
||||
s_gs->ReadFIFO(mem, 1);
|
||||
|
||||
#ifdef _LINUX
|
||||
s_gs->m_wnd.DetachContext();
|
||||
#endif
|
||||
}
|
||||
|
||||
EXPORT_C GSreadFIFO2(uint8* mem, uint32 size)
|
||||
{
|
||||
#ifdef _LINUX
|
||||
// FIXME called from EE core thread not MTGS which cause
|
||||
// invalidate data for opengl
|
||||
if (theApp.GetConfig("renderer", 0) / 3 == 4) {
|
||||
#ifdef OGL_DEBUG
|
||||
fprintf(stderr, "Disable FIFO2(%d) on opengl\n", size);
|
||||
#endif
|
||||
//return;
|
||||
}
|
||||
s_gs->m_wnd.AttachContext();
|
||||
#endif
|
||||
|
||||
s_gs->ReadFIFO(mem, size);
|
||||
|
||||
#ifdef _LINUX
|
||||
s_gs->m_wnd.DetachContext();
|
||||
#endif
|
||||
}
|
||||
|
||||
EXPORT_C GSgifTransfer(const uint8* mem, uint32 size)
|
||||
|
@ -1201,3 +1244,217 @@ EXPORT_C GSBenchmark(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow
|
|||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _LINUX
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/timeb.h> // ftime(), struct timeb
|
||||
|
||||
inline unsigned long timeGetTime()
|
||||
{
|
||||
timeb t;
|
||||
ftime(&t);
|
||||
|
||||
return (unsigned long)(t.time*1000 + t.millitm);
|
||||
}
|
||||
|
||||
// Note
|
||||
EXPORT_C GSReplay(char* lpszCmdLine, int renderer)
|
||||
{
|
||||
|
||||
|
||||
// lpszCmdLine:
|
||||
// First parameter is the renderer.
|
||||
// Second parameter is the gs file to load and run.
|
||||
|
||||
//EXPORT_C GSReplay(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
|
||||
#if 0
|
||||
int renderer = -1;
|
||||
|
||||
{
|
||||
char* start = lpszCmdLine;
|
||||
char* end = NULL;
|
||||
long n = strtol(lpszCmdLine, &end, 10);
|
||||
if(end > start) {renderer = n; lpszCmdLine = end;}
|
||||
}
|
||||
|
||||
while(*lpszCmdLine == ' ') lpszCmdLine++;
|
||||
|
||||
::SetPriorityClass(::GetCurrentProcess(), HIGH_PRIORITY_CLASS);
|
||||
#endif
|
||||
// Allow to easyly switch between SW/HW renderer
|
||||
renderer = theApp.GetConfig("renderer", 12);
|
||||
if (renderer != 12 && renderer != 13)
|
||||
{
|
||||
fprintf(stderr, "wrong renderer selected %d\n", renderer);
|
||||
return;
|
||||
}
|
||||
|
||||
if(FILE* fp = fopen(lpszCmdLine, "rb"))
|
||||
{
|
||||
//Console console("GSdx", true);
|
||||
|
||||
GSinit();
|
||||
|
||||
uint8 regs[0x2000];
|
||||
GSsetBaseMem(regs);
|
||||
|
||||
s_vsync = !!theApp.GetConfig("vsync", 0);
|
||||
|
||||
void* hWnd = NULL;
|
||||
|
||||
_GSopen((void**)&hWnd, "", renderer);
|
||||
|
||||
uint32 crc;
|
||||
fread(&crc, 4, 1, fp);
|
||||
GSsetGameCRC(crc, 0);
|
||||
|
||||
GSFreezeData fd;
|
||||
fread(&fd.size, 4, 1, fp);
|
||||
fd.data = new uint8[fd.size];
|
||||
fread(fd.data, fd.size, 1, fp);
|
||||
GSfreeze(FREEZE_LOAD, &fd);
|
||||
delete [] fd.data;
|
||||
|
||||
fread(regs, 0x2000, 1, fp);
|
||||
|
||||
long start = ftell(fp);
|
||||
|
||||
GSvsync(1);
|
||||
|
||||
struct Packet {uint8 type, param; uint32 size, addr; vector<uint8> buff;};
|
||||
|
||||
list<Packet*> packets;
|
||||
vector<uint8> buff;
|
||||
int type;
|
||||
|
||||
while((type = fgetc(fp)) != EOF)
|
||||
{
|
||||
Packet* p = new Packet();
|
||||
|
||||
p->type = (uint8)type;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case 0:
|
||||
|
||||
p->param = (uint8)fgetc(fp);
|
||||
|
||||
fread(&p->size, 4, 1, fp);
|
||||
|
||||
switch(p->param)
|
||||
{
|
||||
case 0:
|
||||
p->buff.resize(0x4000);
|
||||
p->addr = 0x4000 - p->size;
|
||||
fread(&p->buff[p->addr], p->size, 1, fp);
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
p->buff.resize(p->size);
|
||||
fread(&p->buff[0], p->size, 1, fp);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 1:
|
||||
|
||||
p->param = (uint8)fgetc(fp);
|
||||
|
||||
break;
|
||||
|
||||
case 2:
|
||||
|
||||
fread(&p->size, 4, 1, fp);
|
||||
|
||||
break;
|
||||
|
||||
case 3:
|
||||
|
||||
p->buff.resize(0x2000);
|
||||
|
||||
fread(&p->buff[0], 0x2000, 1, fp);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
packets.push_back(p);
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
|
||||
//while(IsWindowVisible(hWnd))
|
||||
//FIXME map?
|
||||
int finished = 2;
|
||||
while(finished > 0)
|
||||
{
|
||||
unsigned long start = timeGetTime();
|
||||
unsigned long frame_number = 0;
|
||||
for(auto i = packets.begin(); i != packets.end(); i++)
|
||||
{
|
||||
Packet* p = *i;
|
||||
|
||||
switch(p->type)
|
||||
{
|
||||
case 0:
|
||||
|
||||
switch(p->param)
|
||||
{
|
||||
case 0: GSgifTransfer1(&p->buff[0], p->addr); break;
|
||||
case 1: GSgifTransfer2(&p->buff[0], p->size / 16); break;
|
||||
case 2: GSgifTransfer3(&p->buff[0], p->size / 16); break;
|
||||
case 3: GSgifTransfer(&p->buff[0], p->size / 16); break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 1:
|
||||
|
||||
GSvsync(p->param);
|
||||
frame_number++;
|
||||
|
||||
break;
|
||||
|
||||
case 2:
|
||||
|
||||
if(buff.size() < p->size) buff.resize(p->size);
|
||||
|
||||
GSreadFIFO2(&buff[0], p->size / 16);
|
||||
|
||||
break;
|
||||
|
||||
case 3:
|
||||
|
||||
memcpy(regs, &p->buff[0], 0x2000);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
unsigned long end = timeGetTime();
|
||||
fprintf(stderr, "The %d frames of the scene was render on %dms\n", frame_number, end - start);
|
||||
fprintf(stderr, "A means of %fms by frame\n", (float)(end - start)/(float)frame_number);
|
||||
|
||||
sleep(1);
|
||||
finished--;
|
||||
}
|
||||
|
||||
|
||||
for(auto i = packets.begin(); i != packets.end(); i++)
|
||||
{
|
||||
delete *i;
|
||||
}
|
||||
|
||||
packets.clear();
|
||||
|
||||
sleep(1);
|
||||
|
||||
GSclose();
|
||||
GSshutdown();
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,922 @@
|
|||
/*
|
||||
* Copyright (C) 2011-2011 Gregory hainaut
|
||||
* Copyright (C) 2007-2009 Gabest
|
||||
*
|
||||
* 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, 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
#include "GSDevice.h"
|
||||
#include "GSTextureOGL.h"
|
||||
#include "GSdx.h"
|
||||
|
||||
class GSBlendStateOGL {
|
||||
// Note: You can also select the index of the draw buffer for which to set the blend setting
|
||||
// We will keep basic the first try
|
||||
bool m_enable;
|
||||
GLenum m_equation_RGB;
|
||||
GLenum m_equation_ALPHA;
|
||||
GLenum m_func_sRGB;
|
||||
GLenum m_func_dRGB;
|
||||
GLenum m_func_sALPHA;
|
||||
GLenum m_func_dALPHA;
|
||||
bool m_r_msk;
|
||||
bool m_b_msk;
|
||||
bool m_g_msk;
|
||||
bool m_a_msk;
|
||||
bool constant_factor;
|
||||
float debug_factor;
|
||||
|
||||
public:
|
||||
|
||||
GSBlendStateOGL() : m_enable(false)
|
||||
, m_equation_RGB(0)
|
||||
, m_equation_ALPHA(GL_FUNC_ADD)
|
||||
, m_func_sRGB(0)
|
||||
, m_func_dRGB(0)
|
||||
, m_func_sALPHA(GL_ONE)
|
||||
, m_func_dALPHA(GL_ZERO)
|
||||
, m_r_msk(GL_TRUE)
|
||||
, m_b_msk(GL_TRUE)
|
||||
, m_g_msk(GL_TRUE)
|
||||
, m_a_msk(GL_TRUE)
|
||||
, constant_factor(false)
|
||||
{}
|
||||
|
||||
void SetRGB(GLenum op, GLenum src, GLenum dst)
|
||||
{
|
||||
m_equation_RGB = op;
|
||||
m_func_sRGB = src;
|
||||
m_func_dRGB = dst;
|
||||
if (IsConstant(src) || IsConstant(dst)) constant_factor = true;
|
||||
}
|
||||
|
||||
void SetALPHA(GLenum op, GLenum src, GLenum dst)
|
||||
{
|
||||
m_equation_ALPHA = op;
|
||||
m_func_sALPHA = src;
|
||||
m_func_dALPHA = dst;
|
||||
}
|
||||
|
||||
void SetMask(bool r, bool g, bool b, bool a) { m_r_msk = r; m_g_msk = g; m_b_msk = b; m_a_msk = a; }
|
||||
|
||||
void RevertOp()
|
||||
{
|
||||
if(m_equation_RGB == GL_FUNC_ADD)
|
||||
m_equation_RGB = GL_FUNC_REVERSE_SUBTRACT;
|
||||
else if(m_equation_RGB == GL_FUNC_REVERSE_SUBTRACT)
|
||||
m_equation_RGB = GL_FUNC_ADD;
|
||||
}
|
||||
|
||||
void EnableBlend() { m_enable = true;}
|
||||
|
||||
bool IsConstant(GLenum factor) { return ((factor == GL_CONSTANT_COLOR) || (factor == GL_ONE_MINUS_CONSTANT_COLOR)); }
|
||||
|
||||
bool HasConstantFactor() { return constant_factor; }
|
||||
|
||||
void SetupColorMask()
|
||||
{
|
||||
glColorMask(m_r_msk, m_g_msk, m_b_msk, m_a_msk);
|
||||
}
|
||||
|
||||
void SetupBlend(float factor)
|
||||
{
|
||||
SetupColorMask();
|
||||
|
||||
if (m_enable) {
|
||||
glEnable(GL_BLEND);
|
||||
if (HasConstantFactor()) {
|
||||
debug_factor = factor;
|
||||
glBlendColor(factor, factor, factor, 0);
|
||||
}
|
||||
|
||||
glBlendEquationSeparate(m_equation_RGB, m_equation_ALPHA);
|
||||
glBlendFuncSeparate(m_func_sRGB, m_func_dRGB, m_func_sALPHA, m_func_dALPHA);
|
||||
} else {
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
}
|
||||
|
||||
char* NameOfParam(GLenum p)
|
||||
{
|
||||
switch (p) {
|
||||
case GL_FUNC_ADD: return "ADD";
|
||||
case GL_FUNC_SUBTRACT: return "SUB";
|
||||
case GL_FUNC_REVERSE_SUBTRACT: return "REV SUB";
|
||||
case GL_ONE: return "ONE";
|
||||
case GL_ZERO: return "ZERO";
|
||||
case GL_SRC1_ALPHA: return "SRC1 ALPHA";
|
||||
case GL_SRC_ALPHA: return "SRC ALPHA";
|
||||
case GL_ONE_MINUS_DST_ALPHA: return "1 - DST ALPHA";
|
||||
case GL_DST_ALPHA: return "DST ALPHA";
|
||||
case GL_DST_COLOR: return "DST COLOR";
|
||||
case GL_ONE_MINUS_SRC1_ALPHA: return "1 - SRC1 ALPHA";
|
||||
case GL_ONE_MINUS_SRC_ALPHA: return "1 - SRC ALPHA";
|
||||
case GL_CONSTANT_COLOR: return "CST";
|
||||
case GL_ONE_MINUS_CONSTANT_COLOR: return "1 - CST";
|
||||
default: return "UKN";
|
||||
}
|
||||
return "UKN";
|
||||
}
|
||||
|
||||
void debug()
|
||||
{
|
||||
if (!m_enable) return;
|
||||
fprintf(stderr,"Blend op: %s; src:%s; dst:%s\n", NameOfParam(m_equation_RGB), NameOfParam(m_func_sRGB), NameOfParam(m_func_dRGB));
|
||||
if (HasConstantFactor()) fprintf(stderr, "Blend constant: %f\n", debug_factor);
|
||||
fprintf(stderr,"Mask. R:%d B:%d G:%d A:%d\n", m_r_msk, m_b_msk, m_g_msk, m_a_msk);
|
||||
}
|
||||
};
|
||||
|
||||
class GSDepthStencilOGL {
|
||||
bool m_depth_enable;
|
||||
GLenum m_depth_func;
|
||||
GLboolean m_depth_mask;
|
||||
// Note front face and back might be split but it seems they have same parameter configuration
|
||||
bool m_stencil_enable;
|
||||
GLuint m_stencil_mask;
|
||||
GLuint m_stencil_func;
|
||||
GLuint m_stencil_ref;
|
||||
GLuint m_stencil_sfail_op;
|
||||
GLuint m_stencil_spass_dfail_op;
|
||||
GLuint m_stencil_spass_dpass_op;
|
||||
|
||||
char* NameOfParam(GLenum p)
|
||||
{
|
||||
switch(p) {
|
||||
case GL_NEVER: return "NEVER";
|
||||
case GL_ALWAYS: return "ALWAYS";
|
||||
case GL_GEQUAL: return "GEQUAL";
|
||||
case GL_GREATER: return "GREATER";
|
||||
case GL_KEEP: return "KEEP";
|
||||
case GL_EQUAL: return "EQUAL";
|
||||
case GL_REPLACE: return "REPLACE";
|
||||
default: return "UKN";
|
||||
}
|
||||
return "UKN";
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
GSDepthStencilOGL() : m_depth_enable(false)
|
||||
, m_depth_func(0)
|
||||
, m_depth_mask(0)
|
||||
, m_stencil_enable(false)
|
||||
, m_stencil_mask(1)
|
||||
, m_stencil_func(0)
|
||||
, m_stencil_ref(0)
|
||||
, m_stencil_sfail_op(GL_KEEP)
|
||||
, m_stencil_spass_dfail_op(GL_KEEP)
|
||||
, m_stencil_spass_dpass_op(GL_KEEP)
|
||||
{}
|
||||
|
||||
void EnableDepth() { m_depth_enable = true; }
|
||||
void EnableStencil() { m_stencil_enable = true; }
|
||||
|
||||
void SetDepth(GLenum func, GLboolean mask) { m_depth_func = func; m_depth_mask = mask; }
|
||||
void SetStencil(GLuint func, GLuint pass) { m_stencil_func = func; m_stencil_spass_dpass_op = pass; }
|
||||
|
||||
void SetupDepth()
|
||||
{
|
||||
if (m_depth_enable) {
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc(m_depth_func);
|
||||
glDepthMask(m_depth_mask);
|
||||
} else
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
void SetupStencil(uint8 sref)
|
||||
{
|
||||
uint ref = sref;
|
||||
if (m_stencil_enable) {
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
glStencilFunc(m_stencil_func, ref, m_stencil_mask);
|
||||
glStencilOp(m_stencil_sfail_op, m_stencil_spass_dfail_op, m_stencil_spass_dpass_op);
|
||||
} else
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
}
|
||||
|
||||
void debug() { debug_depth(); debug_stencil(); }
|
||||
|
||||
void debug_depth()
|
||||
{
|
||||
if (!m_depth_enable) return;
|
||||
fprintf(stderr, "Depth %s. Mask %x\n", NameOfParam(m_depth_func), m_depth_mask);
|
||||
}
|
||||
|
||||
void debug_stencil()
|
||||
{
|
||||
if (!m_stencil_enable) return;
|
||||
fprintf(stderr, "Stencil %s. Both pass op %s\n", NameOfParam(m_stencil_func), NameOfParam(m_stencil_spass_dpass_op));
|
||||
}
|
||||
};
|
||||
|
||||
class GSUniformBufferOGL {
|
||||
GLuint buffer; // data object
|
||||
GLuint index; // GLSL slot
|
||||
uint size; // size of the data
|
||||
const GLenum target;
|
||||
|
||||
public:
|
||||
GSUniformBufferOGL(GLuint index, uint size) : index(index)
|
||||
, size(size)
|
||||
,target(GL_UNIFORM_BUFFER)
|
||||
{
|
||||
glGenBuffers(1, &buffer);
|
||||
bind();
|
||||
allocate();
|
||||
attach();
|
||||
}
|
||||
|
||||
void bind()
|
||||
{
|
||||
glBindBuffer(target, buffer);
|
||||
}
|
||||
|
||||
void allocate()
|
||||
{
|
||||
glBufferData(target, size, NULL, GL_STREAM_DRAW);
|
||||
}
|
||||
|
||||
void attach()
|
||||
{
|
||||
glBindBufferBase(target, index, buffer);
|
||||
}
|
||||
|
||||
void upload(const void* src)
|
||||
{
|
||||
uint32 flags = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT;
|
||||
uint8* dst = (uint8*) glMapBufferRange(target, 0, size, flags);
|
||||
memcpy(dst, src, size);
|
||||
glUnmapBuffer(target);
|
||||
}
|
||||
|
||||
~GSUniformBufferOGL() {
|
||||
glDeleteBuffers(1, &buffer);
|
||||
}
|
||||
};
|
||||
|
||||
struct GSInputLayoutOGL {
|
||||
GLuint index;
|
||||
GLint size;
|
||||
GLenum type;
|
||||
GLboolean normalize;
|
||||
GLsizei stride;
|
||||
const GLvoid* offset;
|
||||
};
|
||||
|
||||
class GSVertexBufferStateOGL {
|
||||
class GSBufferOGL {
|
||||
size_t m_stride;
|
||||
size_t m_start;
|
||||
size_t m_count;
|
||||
size_t m_limit;
|
||||
GLenum m_target;
|
||||
GLuint m_buffer;
|
||||
size_t m_default_size;
|
||||
|
||||
public:
|
||||
GSBufferOGL(GLenum target, size_t stride) :
|
||||
m_stride(stride)
|
||||
, m_start(0)
|
||||
, m_count(0)
|
||||
, m_limit(0)
|
||||
, m_target(target)
|
||||
{
|
||||
glGenBuffers(1, &m_buffer);
|
||||
// Opengl works best with 1-4MB buffer.
|
||||
m_default_size = 2 * 1024 * 1024 / m_stride;
|
||||
}
|
||||
|
||||
~GSBufferOGL() { glDeleteBuffers(1, &m_buffer); }
|
||||
|
||||
void allocate() { allocate(m_default_size); }
|
||||
|
||||
void allocate(size_t new_limit)
|
||||
{
|
||||
m_start = 0;
|
||||
m_limit = new_limit;
|
||||
glBufferData(m_target, m_limit * m_stride, NULL, GL_STREAM_DRAW);
|
||||
}
|
||||
|
||||
void bind()
|
||||
{
|
||||
glBindBuffer(m_target, m_buffer);
|
||||
}
|
||||
|
||||
void upload(const void* src, uint32 count)
|
||||
{
|
||||
// Upload the data to the buffer
|
||||
void* dst;
|
||||
if (Map(&dst, count)) {
|
||||
// FIXME which one to use
|
||||
// GSVector4i::storent(dst, src, m_count * m_stride);
|
||||
memcpy(dst, src, m_stride*m_count);
|
||||
Unmap();
|
||||
}
|
||||
}
|
||||
|
||||
bool Map(void** pointer, uint32 count ) {
|
||||
#ifdef OGL_DEBUG
|
||||
GLint b_size = -1;
|
||||
glGetBufferParameteriv(m_target, GL_BUFFER_SIZE, &b_size);
|
||||
|
||||
if (b_size <= 0) return false;
|
||||
#endif
|
||||
|
||||
m_count = count;
|
||||
|
||||
// Note: For an explanation of the map flag
|
||||
// see http://www.opengl.org/wiki/Buffer_Object_Streaming
|
||||
uint32 map_flags = GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
|
||||
|
||||
// Current GPU buffer is really too small need to allocate a new one
|
||||
if (m_count > m_limit) {
|
||||
allocate(std::max<int>(m_count * 3 / 2, m_default_size));
|
||||
|
||||
} else if (m_count > (m_limit - m_start) ) {
|
||||
// Not enough left free room. Just go back at the beginning
|
||||
m_start = 0;
|
||||
|
||||
// Tell the driver that it can orphan previous buffer and restart from a scratch buffer.
|
||||
// Technically the buffer will not be accessible by the application anymore but the
|
||||
// GL will effectively remove it when draws call are finised.
|
||||
map_flags |= GL_MAP_INVALIDATE_BUFFER_BIT;
|
||||
} else {
|
||||
// Tell the driver that it doesn't need to contain any valid buffer data, and that you promise to write the entire range you map
|
||||
map_flags |= GL_MAP_INVALIDATE_RANGE_BIT;
|
||||
}
|
||||
|
||||
// Upload the data to the buffer
|
||||
*pointer = (uint8*) glMapBufferRange(m_target, m_stride*m_start, m_stride*m_count, map_flags);
|
||||
//fprintf(stderr, "Map %x from %d to %d\n", *pointer, m_start, m_start+m_count);
|
||||
#ifdef OGL_DEBUG
|
||||
if (*pointer == NULL) {
|
||||
fprintf(stderr, "CRITICAL ERROR map failed for vb!!!\n");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void Unmap() { glUnmapBuffer(m_target); }
|
||||
|
||||
void EndScene()
|
||||
{
|
||||
m_start += m_count;
|
||||
m_count = 0;
|
||||
}
|
||||
|
||||
void Draw(GLenum mode)
|
||||
{
|
||||
glDrawArrays(mode, m_start, m_count);
|
||||
}
|
||||
|
||||
void Draw(GLenum mode, GLint basevertex)
|
||||
{
|
||||
glDrawElementsBaseVertex(mode, m_count, GL_UNSIGNED_INT, (void*)(m_start * m_stride), basevertex);
|
||||
}
|
||||
|
||||
void Draw(GLenum mode, GLint basevertex, int offset, int count)
|
||||
{
|
||||
glDrawElementsBaseVertex(mode, count, GL_UNSIGNED_INT, (void*)((m_start + offset) * m_stride), basevertex);
|
||||
}
|
||||
|
||||
size_t GetStart() { return m_start; }
|
||||
|
||||
void debug()
|
||||
{
|
||||
fprintf(stderr, "data buffer: start %d, count %d\n", m_start, m_count);
|
||||
}
|
||||
|
||||
} *m_vb, *m_ib;
|
||||
|
||||
GLuint m_va;
|
||||
GLenum m_topology;
|
||||
|
||||
public:
|
||||
GSVertexBufferStateOGL(size_t stride, GSInputLayoutOGL* layout, uint32 layout_nbr)
|
||||
{
|
||||
glGenVertexArrays(1, &m_va);
|
||||
|
||||
m_vb = new GSBufferOGL(GL_ARRAY_BUFFER, stride);
|
||||
m_ib = new GSBufferOGL(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32));
|
||||
|
||||
bind();
|
||||
// Note: index array are part of the VA state so it need to be bind only once.
|
||||
m_ib->bind();
|
||||
|
||||
m_vb->allocate();
|
||||
m_ib->allocate();
|
||||
set_internal_format(layout, layout_nbr);
|
||||
}
|
||||
|
||||
void bind()
|
||||
{
|
||||
glBindVertexArray(m_va);
|
||||
m_vb->bind();
|
||||
}
|
||||
|
||||
void set_internal_format(GSInputLayoutOGL* layout, uint32 layout_nbr)
|
||||
{
|
||||
for (int i = 0; i < layout_nbr; i++) {
|
||||
// Note this function need both a vertex array object and a GL_ARRAY_BUFFER buffer
|
||||
glEnableVertexAttribArray(layout[i].index);
|
||||
switch (layout[i].type) {
|
||||
case GL_UNSIGNED_SHORT:
|
||||
case GL_UNSIGNED_INT:
|
||||
// Rule: when shader use integral (not normalized) you must use glVertexAttribIPointer (note the extra I)
|
||||
glVertexAttribIPointer(layout[i].index, layout[i].size, layout[i].type, layout[i].stride, layout[i].offset);
|
||||
break;
|
||||
default:
|
||||
glVertexAttribPointer(layout[i].index, layout[i].size, layout[i].type, layout[i].normalize, layout[i].stride, layout[i].offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EndScene()
|
||||
{
|
||||
m_vb->EndScene();
|
||||
m_ib->EndScene();
|
||||
}
|
||||
|
||||
void DrawPrimitive() { m_vb->Draw(m_topology); }
|
||||
|
||||
void DrawIndexedPrimitive() { m_ib->Draw(m_topology, m_vb->GetStart() ); }
|
||||
|
||||
void DrawIndexedPrimitive(int offset, int count) { m_ib->Draw(m_topology, m_vb->GetStart(), offset, count ); }
|
||||
|
||||
void SetTopology(GLenum topology) { m_topology = topology; }
|
||||
|
||||
void UploadVB(const void* vertices, size_t count) { m_vb->upload(vertices, count); }
|
||||
|
||||
void UploadIB(const void* index, size_t count) { m_ib->upload(index, count); }
|
||||
|
||||
bool MapVB(void **pointer, size_t count) { return m_vb->Map(pointer, count); }
|
||||
|
||||
void UnmapVB() { m_vb->Unmap(); }
|
||||
|
||||
~GSVertexBufferStateOGL()
|
||||
{
|
||||
glDeleteVertexArrays(1, &m_va);
|
||||
}
|
||||
|
||||
void debug()
|
||||
{
|
||||
string topo;
|
||||
switch (m_topology) {
|
||||
case GL_POINTS:
|
||||
topo = "point";
|
||||
break;
|
||||
case GL_LINES:
|
||||
topo = "line";
|
||||
break;
|
||||
case GL_TRIANGLES:
|
||||
topo = "triangle";
|
||||
break;
|
||||
case GL_TRIANGLE_STRIP:
|
||||
topo = "triangle strip";
|
||||
break;
|
||||
}
|
||||
m_vb->debug();
|
||||
m_ib->debug();
|
||||
fprintf(stderr, "primitives of %s\n", topo.c_str());
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
class GSDeviceOGL : public GSDevice
|
||||
{
|
||||
public:
|
||||
__aligned(struct, 32) VSConstantBuffer
|
||||
{
|
||||
GSVector4 VertexScale;
|
||||
GSVector4 VertexOffset;
|
||||
GSVector4 TextureScale;
|
||||
|
||||
VSConstantBuffer()
|
||||
{
|
||||
VertexScale = GSVector4::zero();
|
||||
VertexOffset = GSVector4::zero();
|
||||
TextureScale = GSVector4::zero();
|
||||
}
|
||||
|
||||
__forceinline bool Update(const VSConstantBuffer* cb)
|
||||
{
|
||||
GSVector4i* a = (GSVector4i*)this;
|
||||
GSVector4i* b = (GSVector4i*)cb;
|
||||
|
||||
GSVector4i b0 = b[0];
|
||||
GSVector4i b1 = b[1];
|
||||
GSVector4i b2 = b[2];
|
||||
|
||||
if(!((a[0] == b0) & (a[1] == b1) & (a[2] == b2)).alltrue())
|
||||
{
|
||||
a[0] = b0;
|
||||
a[1] = b1;
|
||||
a[2] = b2;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct VSSelector
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32 bppz:2;
|
||||
uint32 tme:1;
|
||||
uint32 fst:1;
|
||||
uint32 logz:1;
|
||||
uint32 rtcopy:1;
|
||||
uint32 wildhack:2;
|
||||
};
|
||||
|
||||
uint32 key;
|
||||
};
|
||||
|
||||
operator uint32() {return key & 0x3f;}
|
||||
|
||||
VSSelector() : key(0) {}
|
||||
};
|
||||
|
||||
__aligned(struct, 32) PSConstantBuffer
|
||||
{
|
||||
GSVector4 FogColor_AREF;
|
||||
GSVector4 HalfTexel;
|
||||
GSVector4 WH;
|
||||
GSVector4 MinMax;
|
||||
GSVector4 MinF_TA;
|
||||
GSVector4i MskFix;
|
||||
|
||||
PSConstantBuffer()
|
||||
{
|
||||
FogColor_AREF = GSVector4::zero();
|
||||
HalfTexel = GSVector4::zero();
|
||||
WH = GSVector4::zero();
|
||||
MinMax = GSVector4::zero();
|
||||
MinF_TA = GSVector4::zero();
|
||||
MskFix = GSVector4i::zero();
|
||||
}
|
||||
|
||||
__forceinline bool Update(const PSConstantBuffer* cb)
|
||||
{
|
||||
GSVector4i* a = (GSVector4i*)this;
|
||||
GSVector4i* b = (GSVector4i*)cb;
|
||||
|
||||
GSVector4i b0 = b[0];
|
||||
GSVector4i b1 = b[1];
|
||||
GSVector4i b2 = b[2];
|
||||
GSVector4i b3 = b[3];
|
||||
GSVector4i b4 = b[4];
|
||||
GSVector4i b5 = b[5];
|
||||
|
||||
if(!((a[0] == b0) /*& (a[1] == b1)*/ & (a[2] == b2) & (a[3] == b3) & (a[4] == b4) & (a[5] == b5)).alltrue()) // if WH matches HalfTexel does too
|
||||
{
|
||||
a[0] = b0;
|
||||
a[1] = b1;
|
||||
a[2] = b2;
|
||||
a[3] = b3;
|
||||
a[4] = b4;
|
||||
a[5] = b5;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct GSSelector
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32 iip:1;
|
||||
uint32 prim:2;
|
||||
};
|
||||
|
||||
uint32 key;
|
||||
};
|
||||
|
||||
operator uint32() {return key & 0x7;}
|
||||
|
||||
GSSelector() : key(0) {}
|
||||
};
|
||||
|
||||
struct PSSelector
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32 fst:1;
|
||||
uint32 wms:2;
|
||||
uint32 wmt:2;
|
||||
uint32 fmt:3;
|
||||
uint32 aem:1;
|
||||
uint32 tfx:3;
|
||||
uint32 tcc:1;
|
||||
uint32 atst:3;
|
||||
uint32 fog:1;
|
||||
uint32 clr1:1;
|
||||
uint32 fba:1;
|
||||
uint32 aout:1;
|
||||
uint32 rt:1;
|
||||
uint32 ltf:1;
|
||||
uint32 colclip:2;
|
||||
uint32 date:2;
|
||||
uint32 spritehack:1;
|
||||
};
|
||||
|
||||
uint32 key;
|
||||
};
|
||||
|
||||
operator uint32() {return key & 0x3ffffff;}
|
||||
|
||||
PSSelector() : key(0) {}
|
||||
};
|
||||
|
||||
struct PSSamplerSelector
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32 tau:1;
|
||||
uint32 tav:1;
|
||||
uint32 ltf:1;
|
||||
};
|
||||
|
||||
uint32 key;
|
||||
};
|
||||
|
||||
operator uint32() {return key & 0x7;}
|
||||
|
||||
PSSamplerSelector() : key(0) {}
|
||||
};
|
||||
|
||||
struct OMDepthStencilSelector
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32 ztst:2;
|
||||
uint32 zwe:1;
|
||||
uint32 date:1;
|
||||
uint32 fba:1;
|
||||
};
|
||||
|
||||
uint32 key;
|
||||
};
|
||||
|
||||
operator uint32() {return key & 0x1f;}
|
||||
|
||||
OMDepthStencilSelector() : key(0) {}
|
||||
};
|
||||
|
||||
struct OMBlendSelector
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32 abe:1;
|
||||
uint32 a:2;
|
||||
uint32 b:2;
|
||||
uint32 c:2;
|
||||
uint32 d:2;
|
||||
uint32 wr:1;
|
||||
uint32 wg:1;
|
||||
uint32 wb:1;
|
||||
uint32 wa:1;
|
||||
uint32 negative:1;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 _pad:1;
|
||||
uint32 abcd:8;
|
||||
uint32 wrgba:4;
|
||||
};
|
||||
|
||||
uint32 key;
|
||||
};
|
||||
|
||||
operator uint32() {return key & 0x3fff;}
|
||||
|
||||
OMBlendSelector() : key(0) {}
|
||||
|
||||
bool IsCLR1() const
|
||||
{
|
||||
return (key & 0x19f) == 0x93; // abe == 1 && a == 1 && b == 2 && d == 1
|
||||
}
|
||||
};
|
||||
|
||||
struct D3D9Blend {int bogus, op, src, dst;};
|
||||
static const D3D9Blend m_blendMapD3D9[3*3*3*3];
|
||||
|
||||
private:
|
||||
uint32 m_msaa; // Level of Msaa
|
||||
|
||||
bool m_free_window;
|
||||
GSWnd* m_window;
|
||||
|
||||
GLuint m_pipeline; // pipeline to attach program shader
|
||||
GLuint m_fbo; // frame buffer container
|
||||
GLuint m_fbo_read; // frame buffer container only for reading
|
||||
|
||||
GSVertexBufferStateOGL* m_vb; // vb_state for HW renderer
|
||||
GSVertexBufferStateOGL* m_vb_sr; // vb_state for StretchRect
|
||||
|
||||
struct {
|
||||
GLuint ps[2]; // program object
|
||||
GSUniformBufferOGL* cb; // uniform buffer object
|
||||
GSBlendStateOGL* bs;
|
||||
} m_merge_obj;
|
||||
|
||||
struct {
|
||||
GLuint ps[4]; // program object
|
||||
GSUniformBufferOGL* cb; // uniform buffer object
|
||||
} m_interlace;
|
||||
|
||||
struct {
|
||||
GLuint vs; // program object
|
||||
GLuint ps[8]; // program object
|
||||
GLuint ln; // sampler object
|
||||
GLuint pt; // sampler object
|
||||
GLuint gs;
|
||||
GSDepthStencilOGL* dss;
|
||||
GSBlendStateOGL* bs;
|
||||
} m_convert;
|
||||
|
||||
struct {
|
||||
GLuint ps;
|
||||
GSUniformBufferOGL *cb;
|
||||
} m_fxaa;
|
||||
|
||||
struct {
|
||||
GSDepthStencilOGL* dss;
|
||||
GSBlendStateOGL* bs;
|
||||
} m_date;
|
||||
|
||||
struct
|
||||
{
|
||||
GLuint ps;
|
||||
GSUniformBufferOGL *cb;
|
||||
} m_shadeboost;
|
||||
|
||||
|
||||
|
||||
struct {
|
||||
GSVertexBufferStateOGL* vb;
|
||||
GLuint vs; // program
|
||||
GSUniformBufferOGL* cb; // uniform current buffer
|
||||
GLuint gs; // program
|
||||
// FIXME texture binding. Maybe not equivalent for the state but the best I could find.
|
||||
GSTextureOGL* ps_srv[3];
|
||||
// ID3D11ShaderResourceView* ps_srv[3];
|
||||
GLuint ps; // program
|
||||
GLuint ps_ss[3]; // sampler
|
||||
GSVector2i viewport;
|
||||
GSVector4i scissor;
|
||||
GSDepthStencilOGL* dss;
|
||||
uint8 sref;
|
||||
GSBlendStateOGL* bs;
|
||||
float bf;
|
||||
// FIXME texture attachment in the FBO
|
||||
// ID3D11RenderTargetView* rtv;
|
||||
// ID3D11DepthStencilView* dsv;
|
||||
GSTextureOGL* rtv;
|
||||
GSTextureOGL* dsv;
|
||||
GLuint fbo;
|
||||
GLenum draw;
|
||||
} m_state;
|
||||
|
||||
bool m_srv_changed;
|
||||
bool m_ss_changed;
|
||||
|
||||
hash_map<uint32, GLuint > m_vs;
|
||||
hash_map<uint32, GLuint > m_gs;
|
||||
hash_map<uint32, GLuint > m_ps;
|
||||
hash_map<uint32, GLuint > m_ps_ss;
|
||||
hash_map<uint32, GSDepthStencilOGL* > m_om_dss;
|
||||
hash_map<uint32, GSBlendStateOGL* > m_om_bs;
|
||||
|
||||
GLuint m_palette_ss;
|
||||
GLuint m_rt_ss;
|
||||
|
||||
GSUniformBufferOGL* m_vs_cb;
|
||||
GSUniformBufferOGL* m_ps_cb;
|
||||
|
||||
VSConstantBuffer m_vs_cb_cache;
|
||||
PSConstantBuffer m_ps_cb_cache;
|
||||
|
||||
protected:
|
||||
GSTexture* CreateSurface(int type, int w, int h, bool msaa, int format);
|
||||
GSTexture* FetchSurface(int type, int w, int h, bool msaa, int format);
|
||||
void DoMerge(GSTexture* st[2], GSVector4* sr, GSTexture* dt, GSVector4* dr, bool slbg, bool mmod, const GSVector4& c);
|
||||
void DoInterlace(GSTexture* st, GSTexture* dt, int shader, bool linear, float yoffset = 0);
|
||||
void DoShadeBoost(GSTexture* st, GSTexture* dt);
|
||||
|
||||
public:
|
||||
GSDeviceOGL();
|
||||
virtual ~GSDeviceOGL();
|
||||
|
||||
void CheckDebugLog();
|
||||
static void DebugOutputToFile(unsigned int source, unsigned int type, unsigned int id, unsigned int severity, const char* message);
|
||||
void DebugOutput();
|
||||
void DebugInput();
|
||||
void DebugBB();
|
||||
|
||||
bool HasStencil() { return true; }
|
||||
bool HasDepth32() { return true; }
|
||||
|
||||
bool Create(GSWnd* wnd);
|
||||
bool Reset(int w, int h);
|
||||
void Flip();
|
||||
|
||||
void DrawPrimitive();
|
||||
void DrawIndexedPrimitive();
|
||||
void DrawIndexedPrimitive(int offset, int count);
|
||||
|
||||
void ClearRenderTarget(GSTexture* t, const GSVector4& c);
|
||||
void ClearRenderTarget(GSTexture* t, uint32 c);
|
||||
void ClearDepth(GSTexture* t, float c);
|
||||
void ClearStencil(GSTexture* t, uint8 c);
|
||||
|
||||
GSTexture* CreateRenderTarget(int w, int h, bool msaa, int format = 0);
|
||||
GSTexture* CreateDepthStencil(int w, int h, bool msaa, int format = 0);
|
||||
GSTexture* CreateTexture(int w, int h, int format = 0);
|
||||
GSTexture* CreateOffscreen(int w, int h, int format = 0);
|
||||
|
||||
GSTexture* CopyOffscreen(GSTexture* src, const GSVector4& sr, int w, int h, int format = 0);
|
||||
|
||||
void CopyRect(GSTexture* st, GSTexture* dt, const GSVector4i& r);
|
||||
void StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, int shader = 0, bool linear = true);
|
||||
void StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, GLuint ps, bool linear = true);
|
||||
void StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, GLuint ps, GSBlendStateOGL* bs, bool linear = true);
|
||||
|
||||
void SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1* vertices, bool datm);
|
||||
|
||||
GSTexture* Resolve(GSTexture* t);
|
||||
|
||||
void CompileShaderFromSource(const std::string& glsl_file, const std::string& entry, GLenum type, GLuint* program, const std::string& macro_sel = "");
|
||||
|
||||
void EndScene();
|
||||
|
||||
void IASetPrimitiveTopology(GLenum topology);
|
||||
void IASetVertexBuffer(const void* vertices, size_t count);
|
||||
bool IAMapVertexBuffer(void** vertex, size_t stride, size_t count);
|
||||
void IAUnmapVertexBuffer();
|
||||
void IASetIndexBuffer(const void* index, size_t count);
|
||||
void IASetVertexState(GSVertexBufferStateOGL* vb = NULL);
|
||||
|
||||
void SetUniformBuffer(GSUniformBufferOGL* cb);
|
||||
|
||||
void VSSetShader(GLuint vs);
|
||||
void GSSetShader(GLuint gs);
|
||||
|
||||
void PSSetShaderResources(GSTexture* sr0, GSTexture* sr1);
|
||||
void PSSetShaderResource(int i, GSTexture* sr);
|
||||
void PSSetSamplerState(GLuint ss0, GLuint ss1, GLuint ss2 = 0);
|
||||
void PSSetShader(GLuint ps);
|
||||
|
||||
void OMSetFBO(GLuint fbo, GLenum buffer = GL_COLOR_ATTACHMENT0);
|
||||
void OMSetDepthStencilState(GSDepthStencilOGL* dss, uint8 sref);
|
||||
void OMSetBlendState(GSBlendStateOGL* bs, float bf);
|
||||
void OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i* scissor = NULL);
|
||||
|
||||
|
||||
void CreateTextureFX();
|
||||
void SetupIA(const void* vertex, int vertex_count, const uint32* index, int index_count, int prim);
|
||||
void SetupVS(VSSelector sel, const VSConstantBuffer* cb);
|
||||
void SetupGS(GSSelector sel);
|
||||
void SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel);
|
||||
void SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, uint8 afix);
|
||||
};
|
|
@ -22,6 +22,7 @@
|
|||
#include "stdafx.h"
|
||||
#include "GSDeviceSDL.h"
|
||||
|
||||
#ifdef ENABLE_SDL_DEV
|
||||
GSDeviceSDL::GSDeviceSDL()
|
||||
: m_free_window(false)
|
||||
, m_window(NULL)
|
||||
|
@ -230,3 +231,4 @@ void GSDeviceSDL::Flip()
|
|||
{
|
||||
SDL_RenderPresent(m_renderer);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#ifdef ENABLE_SDL_DEV
|
||||
|
||||
#include "GSDeviceSW.h"
|
||||
#include "../../3rdparty/SDL-1.3.0-5387/include/SDL.h"
|
||||
|
||||
|
@ -52,4 +54,5 @@ public:
|
|||
bool Reset(int w, int h);
|
||||
void Present(GSTexture* st, GSTexture* dt, const GSVector4& dr, int shader = 0);
|
||||
void Flip();
|
||||
};
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -22,6 +22,14 @@
|
|||
#include "stdafx.h"
|
||||
#include <gtk/gtk.h>
|
||||
#include "GSdx.h"
|
||||
#include "GSLinuxLogo.h"
|
||||
|
||||
GtkWidget *msaa_combo_box, *render_combo_box, *filter_combo_box;
|
||||
GtkWidget *shadeboost_check, *paltex_check, *fba_check, *aa_check, *native_res_check;
|
||||
GtkWidget *sb_contrast, *sb_brightness, *sb_saturation;
|
||||
GtkWidget *resx_spin, *resy_spin;
|
||||
|
||||
GtkWidget *hack_alpha_check, *hack_offset_check, *hack_skipdraw_spin, *hack_msaa_check, *hack_sprite_check, * hack_wild_check, *hack_enble_check;
|
||||
|
||||
static void SysMessage(const char *fmt, ...)
|
||||
{
|
||||
|
@ -40,16 +48,184 @@ static void SysMessage(const char *fmt, ...)
|
|||
gtk_widget_destroy (dialog);
|
||||
}
|
||||
|
||||
GtkWidget* CreateRenderComboBox()
|
||||
{
|
||||
GtkWidget *render_combo_box;
|
||||
int renderer_box_position = 0;
|
||||
|
||||
render_combo_box = gtk_combo_box_new_text ();
|
||||
|
||||
for(size_t i = 6; i < theApp.m_gs_renderers.size(); i++)
|
||||
{
|
||||
const GSSetting& s = theApp.m_gs_renderers[i];
|
||||
|
||||
string label = s.name;
|
||||
|
||||
if(!s.note.empty()) label += format(" (%s)", s.note.c_str());
|
||||
|
||||
// Add some tags to ease users selection
|
||||
switch (i) {
|
||||
// better use opengl instead of SDL
|
||||
case 6:
|
||||
label += " (deprecated)";
|
||||
break;
|
||||
|
||||
// (dev only) for any NULL stuff
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
label += " (debug only)";
|
||||
break;
|
||||
|
||||
// opengl harware is not yet finished
|
||||
case 10:
|
||||
label += " (experimental)";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(render_combo_box), label.c_str());
|
||||
}
|
||||
|
||||
switch (theApp.GetConfig("renderer", 0)) {
|
||||
// Note the value are based on m_gs_renderers vector on GSdx.cpp
|
||||
case 7 : renderer_box_position = 0; break;
|
||||
case 8 : renderer_box_position = 1; break;
|
||||
case 10: renderer_box_position = 2; break;
|
||||
case 11: renderer_box_position = 3; break;
|
||||
case 12: renderer_box_position = 4; break;
|
||||
case 13: renderer_box_position = 5; break;
|
||||
}
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(render_combo_box), renderer_box_position);
|
||||
return render_combo_box;
|
||||
}
|
||||
|
||||
GtkWidget* CreateInterlaceComboBox()
|
||||
{
|
||||
GtkWidget *combo_box;
|
||||
combo_box = gtk_combo_box_new_text ();
|
||||
|
||||
for(size_t i = 0; i < theApp.m_gs_interlace.size(); i++)
|
||||
{
|
||||
const GSSetting& s = theApp.m_gs_interlace[i];
|
||||
|
||||
string label = s.name;
|
||||
|
||||
if(!s.note.empty()) label += format(" (%s)", s.note.c_str());
|
||||
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(combo_box), label.c_str());
|
||||
}
|
||||
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), theApp.GetConfig("interlace", 0));
|
||||
return combo_box;
|
||||
}
|
||||
|
||||
GtkWidget* CreateMsaaComboBox()
|
||||
{
|
||||
GtkWidget *combo_box;
|
||||
combo_box = gtk_combo_box_new_text ();
|
||||
|
||||
// For now, let's just put in the same vaues that show up in the windows combo box.
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(combo_box), "Custom");
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(combo_box), "2x");
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(combo_box), "3x");
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(combo_box), "4x");
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(combo_box), "5x");
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(combo_box), "6x");
|
||||
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), theApp.GetConfig("msaa", 0));
|
||||
return combo_box;
|
||||
}
|
||||
|
||||
GtkWidget* CreateFilterComboBox()
|
||||
{
|
||||
GtkWidget *combo_box;
|
||||
combo_box = gtk_combo_box_new_text ();
|
||||
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(combo_box), "Off");
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(combo_box), "Normal");
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(combo_box), "Forced");
|
||||
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), theApp.GetConfig("filter", 0));
|
||||
return combo_box;
|
||||
}
|
||||
|
||||
void toggle_widget_states( GtkWidget *widget, gpointer callback_data )
|
||||
{
|
||||
int render_type;
|
||||
bool hardware_render = false, software_render = false, sdl_render = false, null_render = false;
|
||||
|
||||
render_type = gtk_combo_box_get_active(GTK_COMBO_BOX(render_combo_box));
|
||||
hardware_render = (render_type == 1 || render_type == 4 || render_type == 7 || render_type == 13);
|
||||
|
||||
if (hardware_render)
|
||||
{
|
||||
gtk_widget_set_sensitive(filter_combo_box, true);
|
||||
gtk_widget_set_sensitive(shadeboost_check, true);
|
||||
gtk_widget_set_sensitive(paltex_check, true);
|
||||
gtk_widget_set_sensitive(fba_check, true);
|
||||
gtk_widget_set_sensitive(native_res_check, true);
|
||||
|
||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(native_res_check)))
|
||||
{
|
||||
gtk_widget_set_sensitive(msaa_combo_box, false);
|
||||
gtk_widget_set_sensitive(resx_spin, false);
|
||||
gtk_widget_set_sensitive(resy_spin, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_set_sensitive(msaa_combo_box, true);
|
||||
|
||||
if (gtk_combo_box_get_active(GTK_COMBO_BOX(msaa_combo_box)) == 0)
|
||||
{
|
||||
gtk_widget_set_sensitive(resx_spin, true);
|
||||
gtk_widget_set_sensitive(resy_spin, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_set_sensitive(resx_spin, false);
|
||||
gtk_widget_set_sensitive(resy_spin, false);
|
||||
}
|
||||
}
|
||||
|
||||
gtk_widget_set_sensitive(sb_brightness,true);
|
||||
gtk_widget_set_sensitive(sb_saturation,true);
|
||||
gtk_widget_set_sensitive(sb_contrast,true);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_set_sensitive(filter_combo_box, false);
|
||||
gtk_widget_set_sensitive(shadeboost_check, false);
|
||||
gtk_widget_set_sensitive(paltex_check, false);
|
||||
gtk_widget_set_sensitive(fba_check, false);
|
||||
|
||||
gtk_widget_set_sensitive(native_res_check, false);
|
||||
gtk_widget_set_sensitive(msaa_combo_box, false);
|
||||
gtk_widget_set_sensitive(resx_spin, false);
|
||||
gtk_widget_set_sensitive(resy_spin, false);
|
||||
|
||||
gtk_widget_set_sensitive(sb_brightness,false);
|
||||
gtk_widget_set_sensitive(sb_saturation,false);
|
||||
gtk_widget_set_sensitive(sb_contrast,false);
|
||||
}
|
||||
}
|
||||
|
||||
bool RunLinuxDialog()
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
GtkWidget *main_frame, *main_box;
|
||||
GtkWidget *render_label, *render_combo_box;
|
||||
GtkWidget *interlace_label, *interlace_combo_box;
|
||||
GtkWidget *swthreads_label, *swthreads_text;
|
||||
GtkWidget *filter_check, *logz_check, *paltex_check, *fba_check, *aa_check, *win_check;
|
||||
GtkWidget *main_box, *res_box, *hw_box, *sw_box;
|
||||
GtkWidget *native_box, *msaa_box, *resxy_box, *renderer_box, *interlace_box, *threads_box, *filter_box;
|
||||
GtkWidget *hw_table, *res_frame, *hw_frame, *sw_frame;
|
||||
GtkWidget *interlace_combo_box, *threads_spin;
|
||||
GtkWidget *interlace_label, *threads_label, *native_label, *msaa_label, *rexy_label, *render_label, *filter_label;
|
||||
|
||||
GtkWidget *hack_table, *hack_skipdraw_label, *hack_box, *hack_frame;
|
||||
int return_value;
|
||||
|
||||
|
||||
GdkPixbuf* logo_pixmap;
|
||||
GtkWidget *logo_image;
|
||||
|
||||
/* Create the widgets */
|
||||
dialog = gtk_dialog_new_with_buttons (
|
||||
"GSdx Config",
|
||||
|
@ -61,107 +237,245 @@ bool RunLinuxDialog()
|
|||
GTK_RESPONSE_REJECT,
|
||||
NULL);
|
||||
|
||||
// The main area for the whole dialog box.
|
||||
main_box = gtk_vbox_new(false, 5);
|
||||
main_frame = gtk_frame_new ("GSdx Config");
|
||||
gtk_container_add (GTK_CONTAINER(main_frame), main_box);
|
||||
|
||||
|
||||
// The Internal resolution frame and container.
|
||||
res_box = gtk_vbox_new(false, 5);
|
||||
res_frame = gtk_frame_new ("OpenGL Internal Resolution (can cause glitches)");
|
||||
gtk_container_add(GTK_CONTAINER(res_frame), res_box);
|
||||
|
||||
// The hardware mode frame, container, and table.
|
||||
hw_box = gtk_vbox_new(false, 5);
|
||||
hw_frame = gtk_frame_new ("Hardware Mode Settings");
|
||||
gtk_container_add(GTK_CONTAINER(hw_frame), hw_box);
|
||||
hw_table = gtk_table_new(5,2, false);
|
||||
gtk_container_add(GTK_CONTAINER(hw_box), hw_table);
|
||||
|
||||
// The software mode frame and container. (It doesn't have enough in it for a table.)
|
||||
sw_box = gtk_vbox_new(false, 5);
|
||||
sw_frame = gtk_frame_new ("Software Mode Settings");
|
||||
gtk_container_add(GTK_CONTAINER(sw_frame), sw_box);
|
||||
|
||||
// The hack frame and container.
|
||||
hack_box = gtk_hbox_new(false, 5);
|
||||
hack_frame = gtk_frame_new ("Hacks");
|
||||
gtk_container_add(GTK_CONTAINER(hack_frame), hack_box);
|
||||
hack_table = gtk_table_new(3,3, false);
|
||||
gtk_container_add(GTK_CONTAINER(hack_box), hack_table);
|
||||
|
||||
// Grab a logo, to make things look nice.
|
||||
logo_pixmap = gdk_pixbuf_from_pixdata(&gsdx_ogl_logo, false, NULL);
|
||||
logo_image = gtk_image_new_from_pixbuf(logo_pixmap);
|
||||
gtk_box_pack_start(GTK_BOX(main_box), logo_image, true, true, 0);
|
||||
|
||||
// Create the renderer combo box and label, and stash them in a box.
|
||||
render_label = gtk_label_new ("Renderer:");
|
||||
render_combo_box = gtk_combo_box_new_text ();
|
||||
render_combo_box = CreateRenderComboBox();
|
||||
renderer_box = gtk_hbox_new(false, 5);
|
||||
// Use gtk_box_pack_start instead of gtk_container_add so it lines up nicely.
|
||||
gtk_box_pack_start(GTK_BOX(renderer_box), render_label, false, false, 5);
|
||||
gtk_box_pack_start(GTK_BOX(renderer_box), render_combo_box, false, false, 5);
|
||||
|
||||
// Create the interlace combo box and label, and stash them in a box.
|
||||
interlace_label = gtk_label_new ("Interlacing (F5):");
|
||||
interlace_combo_box = CreateInterlaceComboBox();
|
||||
interlace_box = gtk_hbox_new(false, 5);
|
||||
gtk_box_pack_start(GTK_BOX(interlace_box), interlace_label, false, false, 5);
|
||||
gtk_box_pack_start(GTK_BOX(interlace_box), interlace_combo_box, false, false, 5);
|
||||
|
||||
for(size_t i = 6; i < theApp.m_gs_renderers.size(); i++)
|
||||
{
|
||||
const GSSetting& s = theApp.m_gs_renderers[i];
|
||||
// Create the filter combo box.
|
||||
filter_label = gtk_label_new ("Texture Filtering:");
|
||||
filter_combo_box = CreateFilterComboBox();
|
||||
filter_box = gtk_hbox_new(false, 5);
|
||||
gtk_box_pack_start(GTK_BOX(filter_box), filter_label, false, false, 5);
|
||||
gtk_box_pack_start(GTK_BOX(filter_box), filter_combo_box, false, false, 0);
|
||||
|
||||
// Create the threading spin box and label, and stash them in a box. (Yes, we do a lot of that.)
|
||||
threads_label = gtk_label_new("Extra rendering threads:");
|
||||
threads_spin = gtk_spin_button_new_with_range(0,100,1);
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(threads_spin), theApp.GetConfig("extrathreads", 0));
|
||||
threads_box = gtk_hbox_new(false, 0);
|
||||
gtk_box_pack_start(GTK_BOX(threads_box), threads_label, false, false, 5);
|
||||
gtk_box_pack_start(GTK_BOX(threads_box), threads_spin, false, false, 5);
|
||||
|
||||
string label = s.name;
|
||||
// A bit of funkiness for the resolution box.
|
||||
native_label = gtk_label_new("Original PS2 Resolution: ");
|
||||
native_res_check = gtk_check_button_new_with_label("Native");
|
||||
native_box = gtk_hbox_new(false, 5);
|
||||
gtk_box_pack_start(GTK_BOX(native_box), native_label, false, false, 5);
|
||||
gtk_box_pack_start(GTK_BOX(native_box), native_res_check, false, false, 5);
|
||||
|
||||
msaa_label = gtk_label_new("Or Use Scaling (broken):");
|
||||
msaa_combo_box = CreateMsaaComboBox();
|
||||
msaa_box = gtk_hbox_new(false, 5);
|
||||
gtk_box_pack_start(GTK_BOX(msaa_box), msaa_label, false, false, 5);
|
||||
gtk_box_pack_start(GTK_BOX(msaa_box), msaa_combo_box, false, false, 5);
|
||||
|
||||
rexy_label = gtk_label_new("Custom Resolution:");
|
||||
resx_spin = gtk_spin_button_new_with_range(256,8192,1);
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(resx_spin), theApp.GetConfig("resx", 1024));
|
||||
resy_spin = gtk_spin_button_new_with_range(256,8192,1);
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(resy_spin), theApp.GetConfig("resy", 1024));
|
||||
resxy_box = gtk_hbox_new(false, 5);
|
||||
gtk_box_pack_start(GTK_BOX(resxy_box), rexy_label, false, false, 5);
|
||||
gtk_box_pack_start(GTK_BOX(resxy_box), resx_spin, false, false, 5);
|
||||
gtk_box_pack_start(GTK_BOX(resxy_box), resy_spin, false, false, 5);
|
||||
|
||||
if(!s.note.empty()) label += format(" (%s)", s.note.c_str());
|
||||
// Create our hack settings.
|
||||
hack_alpha_check = gtk_check_button_new_with_label("Alpha Hack");
|
||||
hack_offset_check = gtk_check_button_new_with_label("Offset Hack");
|
||||
hack_skipdraw_label = gtk_label_new("Skipdraw:");
|
||||
hack_skipdraw_spin = gtk_spin_button_new_with_range(0,1000,1);
|
||||
hack_enble_check = gtk_check_button_new_with_label("Enable User Hacks");
|
||||
hack_wild_check = gtk_check_button_new_with_label("Wild arm Hack");
|
||||
hack_sprite_check = gtk_check_button_new_with_label("Sprite Hack");
|
||||
hack_msaa_check = gtk_check_button_new_with_label("Msaa Hack");
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(hack_skipdraw_spin), theApp.GetConfig("UserHacks_SkipDraw", 0));
|
||||
// Tables are strange. The numbers are for their position: left, right, top, bottom.
|
||||
gtk_table_attach_defaults(GTK_TABLE(hack_table), hack_alpha_check, 0, 1, 0, 1);
|
||||
gtk_table_attach_defaults(GTK_TABLE(hack_table), hack_offset_check, 1, 2, 0, 1);
|
||||
gtk_table_attach_defaults(GTK_TABLE(hack_table), hack_sprite_check, 0, 1, 1, 2);
|
||||
gtk_table_attach_defaults(GTK_TABLE(hack_table), hack_wild_check, 1, 2, 1, 2);
|
||||
// Note: MSAA is not implemented yet. I disable it to make the table square
|
||||
//gtk_table_attach_defaults(GTK_TABLE(hack_table), hack_msaa_check, 2, 3, 1, 2);
|
||||
gtk_table_attach_defaults(GTK_TABLE(hack_table), hack_skipdraw_label, 0, 1, 2, 3);
|
||||
gtk_table_attach_defaults(GTK_TABLE(hack_table), hack_skipdraw_spin, 1, 2, 2, 3);
|
||||
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(render_combo_box), label.c_str());
|
||||
}
|
||||
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(render_combo_box), 0);
|
||||
gtk_container_add(GTK_CONTAINER(main_box), render_label);
|
||||
gtk_container_add(GTK_CONTAINER(main_box), render_combo_box);
|
||||
|
||||
|
||||
interlace_label = gtk_label_new ("Interlace:");
|
||||
interlace_combo_box = gtk_combo_box_new_text ();
|
||||
|
||||
for(size_t i = 0; i < theApp.m_gs_interlace.size(); i++)
|
||||
{
|
||||
const GSSetting& s = theApp.m_gs_interlace[i];
|
||||
|
||||
string label = s.name;
|
||||
|
||||
if(!s.note.empty()) label += format(" (%s)", s.note.c_str());
|
||||
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(interlace_combo_box), label.c_str());
|
||||
}
|
||||
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(interlace_combo_box), theApp.GetConfig("interlace", 0));
|
||||
gtk_container_add(GTK_CONTAINER(main_box), interlace_label);
|
||||
gtk_container_add(GTK_CONTAINER(main_box), interlace_combo_box);
|
||||
|
||||
swthreads_label = gtk_label_new("Extra sw renderer threads:");
|
||||
swthreads_text = gtk_entry_new();
|
||||
char buf[5];
|
||||
sprintf(buf, "%d", theApp.GetConfig("extrathreads", 0));
|
||||
|
||||
gtk_entry_set_text(GTK_ENTRY(swthreads_text), buf);
|
||||
gtk_container_add(GTK_CONTAINER(main_box), swthreads_label);
|
||||
gtk_container_add(GTK_CONTAINER(main_box), swthreads_text);
|
||||
|
||||
|
||||
filter_check = gtk_check_button_new_with_label("Texture Filtering");
|
||||
logz_check = gtk_check_button_new_with_label("Logarithmic Z");
|
||||
// Create our checkboxes.
|
||||
shadeboost_check = gtk_check_button_new_with_label("Shade boost");
|
||||
paltex_check = gtk_check_button_new_with_label("Allow 8 bit textures");
|
||||
fba_check = gtk_check_button_new_with_label("Alpha correction (FBA)");
|
||||
aa_check = gtk_check_button_new_with_label("Edge anti-aliasing");
|
||||
win_check = gtk_check_button_new_with_label("Disable Effects Processing");
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(main_box), filter_check);
|
||||
gtk_container_add(GTK_CONTAINER(main_box), logz_check);
|
||||
gtk_container_add(GTK_CONTAINER(main_box), paltex_check);
|
||||
gtk_container_add(GTK_CONTAINER(main_box), fba_check);
|
||||
gtk_container_add(GTK_CONTAINER(main_box), aa_check);
|
||||
gtk_container_add(GTK_CONTAINER(main_box), win_check);
|
||||
|
||||
// Filter should be 3 states, not 2.
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(filter_check), theApp.GetConfig("filter", 1));
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(logz_check), theApp.GetConfig("logz", 1));
|
||||
aa_check = gtk_check_button_new_with_label("Edge anti-aliasing (AA1)");
|
||||
|
||||
// Set the checkboxes.
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(shadeboost_check), theApp.GetConfig("shadeboost", 1));
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(paltex_check), theApp.GetConfig("paltex", 0));
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fba_check), theApp.GetConfig("fba", 1));
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(aa_check), theApp.GetConfig("aa1", 0));
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(win_check), theApp.GetConfig("windowed", 1));
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(native_res_check), theApp.GetConfig("nativeres", 0));
|
||||
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(hack_alpha_check), theApp.GetConfig("UserHacks_AlphaHack", 0));
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(hack_offset_check), theApp.GetConfig("UserHacks_HalfPixelOffset", 0));
|
||||
|
||||
gtk_container_add (GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), main_frame);
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(hack_enble_check), theApp.GetConfig("UserHacks", 0));
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(hack_msaa_check), theApp.GetConfig("UserHacks_MSAA", 0));
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(hack_wild_check), theApp.GetConfig("UserHacks_WildHack", 0));
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(hack_sprite_check), theApp.GetConfig("UserHacks_SpriteHack", 0));
|
||||
|
||||
// Shadeboost scale
|
||||
sb_brightness = gtk_hscale_new_with_range(0, 200, 10);
|
||||
GtkWidget* sb_brightness_label = gtk_label_new("Shade Boost Brightness");
|
||||
gtk_scale_set_value_pos(GTK_SCALE(sb_brightness), GTK_POS_RIGHT);
|
||||
gtk_range_set_value(GTK_RANGE(sb_brightness), theApp.GetConfig("ShadeBoost_Brightness", 50));
|
||||
|
||||
sb_contrast = gtk_hscale_new_with_range(0, 200, 10);
|
||||
GtkWidget* sb_contrast_label = gtk_label_new("Shade Boost Contrast");
|
||||
gtk_scale_set_value_pos(GTK_SCALE(sb_contrast), GTK_POS_RIGHT);
|
||||
gtk_range_set_value(GTK_RANGE(sb_contrast), theApp.GetConfig("ShadeBoost_Contrast", 50));
|
||||
|
||||
sb_saturation = gtk_hscale_new_with_range(0, 200, 10);
|
||||
GtkWidget* sb_saturation_label = gtk_label_new("Shade Boost Saturation");
|
||||
gtk_scale_set_value_pos(GTK_SCALE(sb_saturation), GTK_POS_RIGHT);
|
||||
gtk_range_set_value(GTK_RANGE(sb_saturation), theApp.GetConfig("ShadeBoost_Saturation", 50));
|
||||
|
||||
// Populate all those boxes we created earlier with widgets.
|
||||
gtk_container_add(GTK_CONTAINER(res_box), native_box);
|
||||
gtk_container_add(GTK_CONTAINER(res_box), msaa_box);
|
||||
gtk_container_add(GTK_CONTAINER(res_box), resxy_box);
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(sw_box), threads_box);
|
||||
gtk_container_add(GTK_CONTAINER(sw_box), aa_check);
|
||||
|
||||
// Tables are strange. The numbers are for their position: left, right, top, bottom.
|
||||
gtk_table_attach_defaults(GTK_TABLE(hw_table), filter_box, 0, 1, 0, 1);
|
||||
gtk_table_attach_defaults(GTK_TABLE(hw_table), shadeboost_check, 1, 2, 0, 1);
|
||||
gtk_table_attach_defaults(GTK_TABLE(hw_table), paltex_check, 0, 1, 1, 2);
|
||||
gtk_table_attach_defaults(GTK_TABLE(hw_table), fba_check, 1, 2, 1, 2);
|
||||
gtk_table_attach_defaults(GTK_TABLE(hw_table), sb_brightness_label, 0, 1, 2, 3);
|
||||
gtk_table_attach_defaults(GTK_TABLE(hw_table), sb_brightness, 1, 2, 2, 3);
|
||||
gtk_table_attach_defaults(GTK_TABLE(hw_table), sb_contrast_label, 0, 1, 3, 4);
|
||||
gtk_table_attach_defaults(GTK_TABLE(hw_table), sb_contrast, 1, 2, 3, 4);
|
||||
gtk_table_attach_defaults(GTK_TABLE(hw_table), sb_saturation_label, 0, 1, 4, 5);
|
||||
gtk_table_attach_defaults(GTK_TABLE(hw_table), sb_saturation, 1, 2, 4, 5);
|
||||
|
||||
|
||||
// Put everything in the big box.
|
||||
gtk_container_add(GTK_CONTAINER(main_box), renderer_box);
|
||||
gtk_container_add(GTK_CONTAINER(main_box), interlace_box);
|
||||
gtk_container_add(GTK_CONTAINER(main_box), res_frame);
|
||||
gtk_container_add(GTK_CONTAINER(main_box), hw_frame);
|
||||
gtk_container_add(GTK_CONTAINER(main_box), sw_frame);
|
||||
|
||||
if (!!theApp.GetConfig("UserHacks", 0))
|
||||
{
|
||||
gtk_container_add(GTK_CONTAINER(main_box), hack_frame);
|
||||
}
|
||||
|
||||
g_signal_connect(render_combo_box, "changed", G_CALLBACK(toggle_widget_states), NULL);
|
||||
g_signal_connect(msaa_combo_box, "changed", G_CALLBACK(toggle_widget_states), NULL);
|
||||
g_signal_connect(native_res_check, "toggled", G_CALLBACK(toggle_widget_states), NULL);
|
||||
// Put the box in the dialog and show it to the world.
|
||||
gtk_container_add (GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), main_box);
|
||||
gtk_widget_show_all (dialog);
|
||||
|
||||
toggle_widget_states(NULL, NULL);
|
||||
return_value = gtk_dialog_run (GTK_DIALOG (dialog));
|
||||
|
||||
if (return_value == GTK_RESPONSE_ACCEPT)
|
||||
{
|
||||
int mode_height = 0, mode_width = 0;
|
||||
|
||||
mode_width = theApp.GetConfig("ModeWidth", 640);
|
||||
mode_height = theApp.GetConfig("ModeHeight", 480);
|
||||
theApp.SetConfig("ModeHeight", mode_height);
|
||||
theApp.SetConfig("ModeWidth", mode_width);
|
||||
|
||||
// Get all the settings from the dialog box.
|
||||
if (gtk_combo_box_get_active(GTK_COMBO_BOX(render_combo_box)) != -1) {
|
||||
// FIXME test current opengl version supported through glxinfo (OpenGL version string:)
|
||||
// Warn the user if 4.2 is not supported and switch back to basic SDL renderer
|
||||
switch (gtk_combo_box_get_active(GTK_COMBO_BOX(render_combo_box))) {
|
||||
// Note the value are based on m_gs_renderers vector on GSdx.cpp
|
||||
case 0: theApp.SetConfig("renderer", 7); break;
|
||||
case 1: theApp.SetConfig("renderer", 8); break;
|
||||
case 2: theApp.SetConfig("renderer", 10); break;
|
||||
case 3: theApp.SetConfig("renderer", 11); break;
|
||||
case 4: theApp.SetConfig("renderer", 12); break;
|
||||
case 5: theApp.SetConfig("renderer", 13); break;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// I'll put the right variable names in later.
|
||||
if (gtk_combo_box_get_active(GTK_COMBO_BOX(render_combo_box)) != -1)
|
||||
renderer = gtk_combo_box_get_active(GTK_COMBO_BOX(render_combo_box));
|
||||
|
||||
// Crash, for some interlace options
|
||||
if (gtk_combo_box_get_active(GTK_COMBO_BOX(interlace_combo_box)) != -1)
|
||||
theApp.SetConfig( "interlace", (int)gtk_combo_box_get_active(GTK_COMBO_BOX(interlace_combo_box)) );
|
||||
#endif
|
||||
theApp.SetConfig( "interlace", (int)gtk_combo_box_get_active(GTK_COMBO_BOX(interlace_combo_box)));
|
||||
|
||||
theApp.SetConfig("extrathreads", (int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(threads_spin)));
|
||||
|
||||
theApp.SetConfig("extrathreads", atoi((char*)gtk_entry_get_text(GTK_ENTRY(swthreads_text))) );
|
||||
theApp.SetConfig("filter", (int)gtk_combo_box_get_active(GTK_COMBO_BOX(filter_combo_box)));
|
||||
theApp.SetConfig("shadeboost", (int)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(shadeboost_check)));
|
||||
theApp.SetConfig("paltex", (int)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(paltex_check)));
|
||||
theApp.SetConfig("fba", (int)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fba_check)));
|
||||
theApp.SetConfig("aa1", (int)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(aa_check)));
|
||||
theApp.SetConfig("nativeres", (int)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(native_res_check)));
|
||||
|
||||
theApp.SetConfig("ShadeBoost_Saturation", (int)gtk_range_get_value(GTK_RANGE(sb_saturation)));
|
||||
theApp.SetConfig("ShadeBoost_Brightness", (int)gtk_range_get_value(GTK_RANGE(sb_brightness)));
|
||||
theApp.SetConfig("ShadeBoost_Contrast", (int)gtk_range_get_value(GTK_RANGE(sb_contrast)));
|
||||
|
||||
theApp.SetConfig("filter", (int)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(filter_check)));
|
||||
theApp.SetConfig("logz", (int)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(logz_check)));
|
||||
theApp.SetConfig("paltex", (int)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(paltex_check)));
|
||||
theApp.SetConfig("fba", (int)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fba_check)));
|
||||
theApp.SetConfig("aa1", (int)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(aa_check)));
|
||||
theApp.SetConfig("windowed", (int)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(win_check)));
|
||||
theApp.SetConfig("msaa", (int)gtk_combo_box_get_active(GTK_COMBO_BOX(msaa_combo_box)));
|
||||
theApp.SetConfig("resx", (int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(resx_spin)));
|
||||
theApp.SetConfig("resy", (int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(resy_spin)));
|
||||
|
||||
theApp.SetConfig("UserHacks_SkipDraw", (int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(hack_skipdraw_spin)));
|
||||
theApp.SetConfig("UserHacks_HalfPixelOffset", (int)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hack_offset_check)));
|
||||
theApp.SetConfig("UserHacks_AlphaHack", (int)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hack_alpha_check)));
|
||||
|
||||
theApp.SetConfig("UserHacks_MSAA", (int)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hack_msaa_check)));
|
||||
theApp.SetConfig("UserHacks_WildHack", (int)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hack_wild_check)));
|
||||
theApp.SetConfig("UserHacks_SpriteHack", (int)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hack_sprite_check)));
|
||||
theApp.SetConfig("UserHacks", (int)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hack_enble_check)));
|
||||
|
||||
// Let's just be windowed for the moment.
|
||||
theApp.SetConfig("windowed", 1);
|
||||
|
||||
gtk_widget_destroy (dialog);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -25,6 +25,8 @@
|
|||
GSRenderer::GSRenderer()
|
||||
: m_dev(NULL)
|
||||
, m_shader(0)
|
||||
, m_shift_key(false)
|
||||
, m_control_key(false)
|
||||
{
|
||||
m_GStitleInfoBuffer[0] = 0;
|
||||
|
||||
|
@ -421,6 +423,10 @@ void GSRenderer::VSync(int field)
|
|||
|
||||
shift = !!(::GetAsyncKeyState(VK_SHIFT) & 0x8000);
|
||||
|
||||
#else
|
||||
|
||||
shift = m_shift_key;
|
||||
|
||||
#endif
|
||||
|
||||
if(!m_dump && shift)
|
||||
|
@ -454,6 +460,10 @@ void GSRenderer::VSync(int field)
|
|||
|
||||
control = !!(::GetAsyncKeyState(VK_CONTROL) & 0x8000);
|
||||
|
||||
#else
|
||||
|
||||
control = m_control_key;
|
||||
|
||||
#endif
|
||||
|
||||
m_dump.VSync(field, !control, m_regs);
|
||||
|
@ -514,9 +524,9 @@ void GSRenderer::EndCapture()
|
|||
|
||||
void GSRenderer::KeyEvent(GSKeyEventData* e)
|
||||
{
|
||||
#ifdef _WINDOWS
|
||||
if(e->type == KEYPRESS)
|
||||
{
|
||||
#ifdef _WINDOWS
|
||||
|
||||
int step = (::GetAsyncKeyState(VK_SHIFT) & 0x8000) ? -1 : 1;
|
||||
|
||||
|
@ -548,10 +558,62 @@ void GSRenderer::KeyEvent(GSKeyEventData* e)
|
|||
return;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// TODO: linux
|
||||
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
if(e->type == KEYPRESS)
|
||||
{
|
||||
int step = m_shift_key ? -1 : 1;
|
||||
|
||||
switch(e->key)
|
||||
{
|
||||
case XK_F5:
|
||||
m_interlace = (m_interlace + 7 + step) % 7;
|
||||
fprintf(stderr, "GSdx: Set deinterlace mode to %d (%s).\n", (int)m_interlace, theApp.m_gs_interlace.at(m_interlace).name.c_str());
|
||||
return;
|
||||
case XK_F6:
|
||||
if( m_wnd.IsManaged() )
|
||||
m_aspectratio = (m_aspectratio + 3 + step) % 3;
|
||||
return;
|
||||
case XK_F7:
|
||||
m_shader = (m_shader + 3 + step) % 3;
|
||||
fprintf(stderr,"GSdx: Set shader %d.\n", (int)m_shader);
|
||||
return;
|
||||
case XK_Delete:
|
||||
m_aa1 = !m_aa1;
|
||||
fprintf(stderr,"GSdx: (Software) aa1 is now %s.\n", m_aa1 ? "enabled" : "disabled");
|
||||
return;
|
||||
case XK_Insert:
|
||||
m_mipmap = !m_mipmap;
|
||||
fprintf(stderr,"GSdx: (Software) mipmapping is now %s.\n", m_mipmap ? "enabled" : "disabled");
|
||||
return;
|
||||
case XK_Prior:
|
||||
m_fxaa = !m_fxaa;
|
||||
fprintf(stderr,"GSdx: fxaa is now %s.\n", m_fxaa ? "enabled" : "disabled");
|
||||
return;
|
||||
case XK_Shift_L:
|
||||
case XK_Shift_R:
|
||||
m_shift_key = true;
|
||||
return;
|
||||
case XK_Control_L:
|
||||
case XK_Control_R:
|
||||
m_control_key = true;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
else if(e->type == KEYRELEASE)
|
||||
{
|
||||
switch(e->key)
|
||||
{
|
||||
case XK_Shift_L:
|
||||
case XK_Shift_R:
|
||||
m_shift_key = false;
|
||||
return;
|
||||
case XK_Control_L:
|
||||
case XK_Control_R:
|
||||
m_control_key = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -35,6 +35,10 @@ class GSRenderer : public GSState
|
|||
|
||||
bool Merge(int field);
|
||||
|
||||
// Only used on linux
|
||||
bool m_shift_key;
|
||||
bool m_control_key;
|
||||
|
||||
protected:
|
||||
int m_interlace;
|
||||
int m_aspectratio;
|
||||
|
|
|
@ -0,0 +1,497 @@
|
|||
/*
|
||||
* Copyright (C) 2011-2011 Gregory hainaut
|
||||
* Copyright (C) 2007-2009 Gabest
|
||||
*
|
||||
* 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, 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
*/
|
||||
|
||||
#include "GSRendererOGL.h"
|
||||
#include "GSRenderer.h"
|
||||
|
||||
|
||||
GSRendererOGL::GSRendererOGL()
|
||||
: GSRendererHW(new GSTextureCacheOGL(this))
|
||||
{
|
||||
m_logz = !!theApp.GetConfig("logz", 0);
|
||||
m_fba = !!theApp.GetConfig("fba", 1);
|
||||
UserHacks_AlphaHack = !!theApp.GetConfig("UserHacks_AlphaHack", 0) && !!theApp.GetConfig("UserHacks", 0);
|
||||
UserHacks_WildHack = !!theApp.GetConfig("UserHacks", 0) ? theApp.GetConfig("UserHacks_WildHack", 0) : 0;
|
||||
m_pixelcenter = GSVector2(-0.5f, -0.5f);
|
||||
}
|
||||
|
||||
bool GSRendererOGL::CreateDevice(GSDevice* dev)
|
||||
{
|
||||
if(!GSRenderer::CreateDevice(dev))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GSRendererOGL::SetupIA()
|
||||
{
|
||||
GSDeviceOGL* dev = (GSDeviceOGL*)m_dev;
|
||||
|
||||
void* ptr = NULL;
|
||||
|
||||
dev->IASetVertexState();
|
||||
|
||||
if(dev->IAMapVertexBuffer(&ptr, sizeof(GSVertex), m_vertex.next))
|
||||
{
|
||||
GSVector4i::storent(ptr, m_vertex.buff, sizeof(GSVertex) * m_vertex.next);
|
||||
|
||||
if(UserHacks_WildHack && !isPackedUV_HackFlag)
|
||||
{
|
||||
GSVertex* RESTRICT d = (GSVertex*)ptr;
|
||||
|
||||
for(unsigned int i = 0; i < m_vertex.next; i++, d++)
|
||||
if(PRIM->TME && PRIM->FST)
|
||||
d->UV &= UserHacks_WildHack == 1 ? 0x3FEF3FEF : 0x3FF73FF7;
|
||||
}
|
||||
|
||||
dev->IAUnmapVertexBuffer();
|
||||
}
|
||||
|
||||
dev->IASetIndexBuffer(m_index.buff, m_index.tail);
|
||||
|
||||
GLenum t;
|
||||
|
||||
switch(m_vt.m_primclass)
|
||||
{
|
||||
case GS_POINT_CLASS:
|
||||
t = GL_POINTS;
|
||||
break;
|
||||
case GS_LINE_CLASS:
|
||||
case GS_SPRITE_CLASS:
|
||||
t = GL_LINES;
|
||||
break;
|
||||
case GS_TRIANGLE_CLASS:
|
||||
t = GL_TRIANGLES;
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
|
||||
dev->IASetPrimitiveTopology(t);
|
||||
}
|
||||
|
||||
|
||||
void GSRendererOGL::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* tex)
|
||||
{
|
||||
GSDrawingEnvironment& env = m_env;
|
||||
GSDrawingContext* context = m_context;
|
||||
|
||||
const GSVector2i& rtsize = rt->GetSize();
|
||||
const GSVector2& rtscale = rt->GetScale();
|
||||
|
||||
bool DATE = m_context->TEST.DATE && context->FRAME.PSM != PSM_PSMCT24;
|
||||
|
||||
//OGL GSTexture* rtcopy = NULL;
|
||||
|
||||
ASSERT(m_dev != NULL);
|
||||
|
||||
GSDeviceOGL* dev = (GSDeviceOGL*)m_dev;
|
||||
|
||||
if(DATE)
|
||||
{
|
||||
// Note at the moment OGL has always stencil. Rt can be disabled
|
||||
if(dev->HasStencil())
|
||||
{
|
||||
GSVector4 s = GSVector4(rtscale.x / rtsize.x, rtscale.y / rtsize.y);
|
||||
GSVector4 o = GSVector4(-1.0f, 1.0f);
|
||||
|
||||
GSVector4 src = ((m_vt.m_min.p.xyxy(m_vt.m_max.p) + o.xxyy()) * s.xyxy()).sat(o.zzyy());
|
||||
GSVector4 dst = src * 2.0f + o.xxxx();
|
||||
|
||||
GSVertexPT1 vertices[] =
|
||||
{
|
||||
#if 0
|
||||
{GSVector4(dst.x, -dst.y, 0.5f, 1.0f), GSVector2(src.x, src.y)},
|
||||
{GSVector4(dst.z, -dst.y, 0.5f, 1.0f), GSVector2(src.z, src.y)},
|
||||
{GSVector4(dst.x, -dst.w, 0.5f, 1.0f), GSVector2(src.x, src.w)},
|
||||
{GSVector4(dst.z, -dst.w, 0.5f, 1.0f), GSVector2(src.z, src.w)},
|
||||
#else
|
||||
{GSVector4(dst.x, -dst.w, 0.5f, 1.0f), GSVector2(src.x, src.y)},
|
||||
{GSVector4(dst.z, -dst.w, 0.5f, 1.0f), GSVector2(src.z, src.y)},
|
||||
{GSVector4(dst.x, -dst.y, 0.5f, 1.0f), GSVector2(src.x, src.w)},
|
||||
{GSVector4(dst.z, -dst.y, 0.5f, 1.0f), GSVector2(src.z, src.w)},
|
||||
#endif
|
||||
};
|
||||
//fprintf(stderr, "DATE A:%fx%f B:%fx%f\n", dst.x, -dst.y, dst.z, -dst.w);
|
||||
//fprintf(stderr, "DATE SR: %f %f %f %f\n", src.x, src.y, src.z, src.w);
|
||||
//fprintf(stderr, "DATE offset: %f\n", o.x);
|
||||
|
||||
dev->SetupDATE(rt, ds, vertices, m_context->TEST.DATM);
|
||||
}
|
||||
else
|
||||
{
|
||||
//OGL rtcopy = dev->CreateRenderTarget(rtsize.x, rtsize.y, false, rt->GetFormat());
|
||||
|
||||
//OGL // I'll use VertexTrace when I consider it more trustworthy
|
||||
|
||||
//OGL dev->CopyRect(rt, rtcopy, GSVector4i(rtsize).zwxy());
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
dev->BeginScene();
|
||||
|
||||
// om
|
||||
|
||||
GSDeviceOGL::OMDepthStencilSelector om_dssel;
|
||||
|
||||
if(context->TEST.ZTE)
|
||||
{
|
||||
om_dssel.ztst = context->TEST.ZTST;
|
||||
om_dssel.zwe = !context->ZBUF.ZMSK;
|
||||
}
|
||||
else
|
||||
{
|
||||
om_dssel.ztst = ZTST_ALWAYS;
|
||||
}
|
||||
|
||||
if(m_fba)
|
||||
{
|
||||
om_dssel.fba = context->FBA.FBA;
|
||||
}
|
||||
|
||||
GSDeviceOGL::OMBlendSelector om_bsel;
|
||||
|
||||
if(!IsOpaque())
|
||||
{
|
||||
om_bsel.abe = PRIM->ABE || PRIM->AA1 && m_vt.m_primclass == GS_LINE_CLASS;
|
||||
|
||||
om_bsel.a = context->ALPHA.A;
|
||||
om_bsel.b = context->ALPHA.B;
|
||||
om_bsel.c = context->ALPHA.C;
|
||||
om_bsel.d = context->ALPHA.D;
|
||||
|
||||
if(env.PABE.PABE)
|
||||
{
|
||||
if(om_bsel.a == 0 && om_bsel.b == 1 && om_bsel.c == 0 && om_bsel.d == 1)
|
||||
{
|
||||
// this works because with PABE alpha blending is on when alpha >= 0x80, but since the pixel shader
|
||||
// cannot output anything over 0x80 (== 1.0) blending with 0x80 or turning it off gives the same result
|
||||
|
||||
om_bsel.abe = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Breath of Fire Dragon Quarter triggers this in battles. Graphics are fine though.
|
||||
//ASSERT(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
om_bsel.wrgba = ~GSVector4i::load((int)context->FRAME.FBMSK).eq8(GSVector4i::xffffffff()).mask();
|
||||
|
||||
// vs
|
||||
|
||||
GSDeviceOGL::VSSelector vs_sel;
|
||||
|
||||
vs_sel.tme = PRIM->TME;
|
||||
vs_sel.fst = PRIM->FST;
|
||||
vs_sel.logz = dev->HasDepth32() ? 0 : m_logz ? 1 : 0;
|
||||
//OGL vs_sel.rtcopy = !!rtcopy;
|
||||
vs_sel.rtcopy = false;
|
||||
|
||||
// The real GS appears to do no masking based on the Z buffer format and writing larger Z values
|
||||
// than the buffer supports seems to be an error condition on the real GS, causing it to crash.
|
||||
// We are probably receiving bad coordinates from VU1 in these cases.
|
||||
|
||||
if(om_dssel.ztst >= ZTST_ALWAYS && om_dssel.zwe)
|
||||
{
|
||||
if(context->ZBUF.PSM == PSM_PSMZ24)
|
||||
{
|
||||
if(m_vt.m_max.p.z > 0xffffff)
|
||||
{
|
||||
ASSERT(m_vt.m_min.p.z > 0xffffff);
|
||||
// Fixme :Following conditional fixes some dialog frame in Wild Arms 3, but may not be what was intended.
|
||||
if (m_vt.m_min.p.z > 0xffffff)
|
||||
{
|
||||
vs_sel.bppz = 1;
|
||||
om_dssel.ztst = ZTST_ALWAYS;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(context->ZBUF.PSM == PSM_PSMZ16 || context->ZBUF.PSM == PSM_PSMZ16S)
|
||||
{
|
||||
if(m_vt.m_max.p.z > 0xffff)
|
||||
{
|
||||
ASSERT(m_vt.m_min.p.z > 0xffff); // sfex capcom logo
|
||||
// Fixme : Same as above, I guess.
|
||||
if (m_vt.m_min.p.z > 0xffff)
|
||||
{
|
||||
vs_sel.bppz = 2;
|
||||
om_dssel.ztst = ZTST_ALWAYS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME Opengl support half pixel center (as dx10). Code could be easier!!!
|
||||
GSDeviceOGL::VSConstantBuffer vs_cb;
|
||||
|
||||
float sx = 2.0f * rtscale.x / (rtsize.x << 4);
|
||||
float sy = 2.0f * rtscale.y / (rtsize.y << 4);
|
||||
float ox = (float)(int)context->XYOFFSET.OFX;
|
||||
float oy = (float)(int)context->XYOFFSET.OFY;
|
||||
float ox2 = 2.0f * m_pixelcenter.x / rtsize.x;
|
||||
float oy2 = 2.0f * m_pixelcenter.y / rtsize.y;
|
||||
|
||||
//This hack subtracts around half a pixel from OFX and OFY. (Cannot do this directly,
|
||||
//because DX10 and DX9 have a different pixel center.)
|
||||
//
|
||||
//The resulting shifted output aligns better with common blending / corona / blurring effects,
|
||||
//but introduces a few bad pixels on the edges.
|
||||
|
||||
if(rt->LikelyOffset)
|
||||
{
|
||||
// DX9 has pixelcenter set to 0.0, so give it some value here
|
||||
|
||||
if(m_pixelcenter.x == 0 && m_pixelcenter.y == 0) { ox2 = -0.0003f; oy2 = -0.0003f; }
|
||||
|
||||
ox2 *= rt->OffsetHack_modx;
|
||||
oy2 *= rt->OffsetHack_mody;
|
||||
}
|
||||
|
||||
vs_cb.VertexScale = GSVector4(sx, -sy, ldexpf(1, -32), 0.0f);
|
||||
vs_cb.VertexOffset = GSVector4(ox * sx + ox2 + 1, -(oy * sy + oy2 + 1), 0.0f, -1.0f);
|
||||
// END of FIXME
|
||||
|
||||
// gs
|
||||
|
||||
GSDeviceOGL::GSSelector gs_sel;
|
||||
|
||||
gs_sel.iip = PRIM->IIP;
|
||||
gs_sel.prim = m_vt.m_primclass;
|
||||
|
||||
// ps
|
||||
|
||||
GSDeviceOGL::PSSelector ps_sel;
|
||||
GSDeviceOGL::PSSamplerSelector ps_ssel;
|
||||
GSDeviceOGL::PSConstantBuffer ps_cb;
|
||||
|
||||
if(DATE)
|
||||
{
|
||||
if(dev->HasStencil())
|
||||
{
|
||||
om_dssel.date = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ps_sel.date = 1 + context->TEST.DATM;
|
||||
}
|
||||
}
|
||||
|
||||
if(env.COLCLAMP.CLAMP == 0 && /* hack */ !tex && PRIM->PRIM != GS_POINTLIST)
|
||||
{
|
||||
ps_sel.colclip = 1;
|
||||
}
|
||||
|
||||
ps_sel.clr1 = om_bsel.IsCLR1();
|
||||
ps_sel.fba = context->FBA.FBA;
|
||||
ps_sel.aout = context->FRAME.PSM == PSM_PSMCT16 || context->FRAME.PSM == PSM_PSMCT16S || (context->FRAME.FBMSK & 0xff000000) == 0x7f000000 ? 1 : 0;
|
||||
|
||||
if(UserHacks_AlphaHack) ps_sel.aout = 1;
|
||||
|
||||
if(PRIM->FGE)
|
||||
{
|
||||
ps_sel.fog = 1;
|
||||
|
||||
ps_cb.FogColor_AREF = GSVector4::rgba32(env.FOGCOL.u32[0]) / 255;
|
||||
}
|
||||
|
||||
if(context->TEST.ATE)
|
||||
{
|
||||
ps_sel.atst = context->TEST.ATST;
|
||||
|
||||
switch(ps_sel.atst)
|
||||
{
|
||||
case ATST_LESS:
|
||||
ps_cb.FogColor_AREF.a = (float)((int)context->TEST.AREF - 1);
|
||||
break;
|
||||
case ATST_GREATER:
|
||||
ps_cb.FogColor_AREF.a = (float)((int)context->TEST.AREF + 1);
|
||||
break;
|
||||
default:
|
||||
ps_cb.FogColor_AREF.a = (float)(int)context->TEST.AREF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ps_sel.atst = ATST_ALWAYS;
|
||||
}
|
||||
|
||||
if(tex)
|
||||
{
|
||||
ps_sel.wms = context->CLAMP.WMS;
|
||||
ps_sel.wmt = context->CLAMP.WMT;
|
||||
ps_sel.fmt = tex->m_fmt;
|
||||
ps_sel.aem = env.TEXA.AEM;
|
||||
ps_sel.tfx = context->TEX0.TFX;
|
||||
ps_sel.tcc = context->TEX0.TCC;
|
||||
ps_sel.ltf = m_filter == 2 ? m_vt.IsLinear() : m_filter;
|
||||
ps_sel.rt = tex->m_target;
|
||||
|
||||
int w = tex->m_texture->GetWidth();
|
||||
int h = tex->m_texture->GetHeight();
|
||||
|
||||
int tw = (int)(1 << context->TEX0.TW);
|
||||
int th = (int)(1 << context->TEX0.TH);
|
||||
|
||||
GSVector4 WH(tw, th, w, h);
|
||||
|
||||
if(PRIM->FST)
|
||||
{
|
||||
vs_cb.TextureScale = GSVector4(1.0f / 16) / WH.xyxy();
|
||||
//Maybe better?
|
||||
//vs_cb.TextureScale = GSVector4(1.0f / 16) * GSVector4(tex->m_texture->GetScale()).xyxy() / WH.zwzw();
|
||||
ps_sel.fst = 1;
|
||||
}
|
||||
|
||||
ps_cb.WH = WH;
|
||||
ps_cb.HalfTexel = GSVector4(-0.5f, 0.5f).xxyy() / WH.zwzw();
|
||||
ps_cb.MskFix = GSVector4i(context->CLAMP.MINU, context->CLAMP.MINV, context->CLAMP.MAXU, context->CLAMP.MAXV);
|
||||
|
||||
GSVector4 clamp(ps_cb.MskFix);
|
||||
GSVector4 ta(env.TEXA & GSVector4i::x000000ff());
|
||||
|
||||
ps_cb.MinMax = clamp / WH.xyxy();
|
||||
ps_cb.MinF_TA = (clamp + 0.5f).xyxy(ta) / WH.xyxy(GSVector4(255, 255));
|
||||
|
||||
ps_ssel.tau = (context->CLAMP.WMS + 3) >> 1;
|
||||
ps_ssel.tav = (context->CLAMP.WMT + 3) >> 1;
|
||||
ps_ssel.ltf = ps_sel.ltf;
|
||||
}
|
||||
else
|
||||
{
|
||||
ps_sel.tfx = 4;
|
||||
}
|
||||
|
||||
// rs
|
||||
|
||||
GSVector4i scissor = GSVector4i(GSVector4(rtscale).xyxy() * context->scissor.in).rintersect(GSVector4i(rtsize).zwxy());
|
||||
|
||||
dev->OMSetRenderTargets(rt, ds, &scissor);
|
||||
dev->PSSetShaderResource(0, tex ? tex->m_texture : NULL);
|
||||
dev->PSSetShaderResource(1, tex ? tex->m_palette : NULL);
|
||||
//OGL dev->PSSetShaderResource(2, rtcopy);
|
||||
|
||||
uint8 afix = context->ALPHA.FIX;
|
||||
|
||||
SetupIA();
|
||||
|
||||
dev->SetupOM(om_dssel, om_bsel, afix);
|
||||
dev->SetupVS(vs_sel, &vs_cb);
|
||||
dev->SetupGS(gs_sel);
|
||||
dev->SetupPS(ps_sel, &ps_cb, ps_ssel);
|
||||
|
||||
// draw
|
||||
|
||||
if(context->TEST.DoFirstPass())
|
||||
{
|
||||
dev->DrawIndexedPrimitive();
|
||||
|
||||
if (env.COLCLAMP.CLAMP == 0 && /* hack */ !tex && PRIM->PRIM != GS_POINTLIST)
|
||||
{
|
||||
GSDeviceOGL::OMBlendSelector om_bselneg(om_bsel);
|
||||
GSDeviceOGL::PSSelector ps_selneg(ps_sel);
|
||||
|
||||
om_bselneg.negative = 1;
|
||||
ps_selneg.colclip = 2;
|
||||
|
||||
dev->SetupOM(om_dssel, om_bselneg, afix);
|
||||
dev->SetupPS(ps_selneg, &ps_cb, ps_ssel);
|
||||
|
||||
dev->DrawIndexedPrimitive();
|
||||
}
|
||||
}
|
||||
|
||||
if(context->TEST.DoSecondPass())
|
||||
{
|
||||
ASSERT(!env.PABE.PABE);
|
||||
|
||||
static const uint32 iatst[] = {1, 0, 5, 6, 7, 2, 3, 4};
|
||||
|
||||
ps_sel.atst = iatst[ps_sel.atst];
|
||||
|
||||
switch(ps_sel.atst)
|
||||
{
|
||||
case ATST_LESS:
|
||||
ps_cb.FogColor_AREF.a = (float)((int)context->TEST.AREF - 1);
|
||||
break;
|
||||
case ATST_GREATER:
|
||||
ps_cb.FogColor_AREF.a = (float)((int)context->TEST.AREF + 1);
|
||||
break;
|
||||
default:
|
||||
ps_cb.FogColor_AREF.a = (float)(int)context->TEST.AREF;
|
||||
break;
|
||||
}
|
||||
|
||||
dev->SetupPS(ps_sel, &ps_cb, ps_ssel);
|
||||
|
||||
bool z = om_dssel.zwe;
|
||||
bool r = om_bsel.wr;
|
||||
bool g = om_bsel.wg;
|
||||
bool b = om_bsel.wb;
|
||||
bool a = om_bsel.wa;
|
||||
|
||||
switch(context->TEST.AFAIL)
|
||||
{
|
||||
case 0: z = r = g = b = a = false; break; // none
|
||||
case 1: z = false; break; // rgba
|
||||
case 2: r = g = b = a = false; break; // z
|
||||
case 3: z = a = false; break; // rgb
|
||||
default: __assume(0);
|
||||
}
|
||||
|
||||
if(z || r || g || b || a)
|
||||
{
|
||||
om_dssel.zwe = z;
|
||||
om_bsel.wr = r;
|
||||
om_bsel.wg = g;
|
||||
om_bsel.wb = b;
|
||||
om_bsel.wa = a;
|
||||
|
||||
dev->SetupOM(om_dssel, om_bsel, afix);
|
||||
|
||||
dev->DrawIndexedPrimitive();
|
||||
|
||||
if (env.COLCLAMP.CLAMP == 0 && /* hack */ !tex && PRIM->PRIM != GS_POINTLIST)
|
||||
{
|
||||
GSDeviceOGL::OMBlendSelector om_bselneg(om_bsel);
|
||||
GSDeviceOGL::PSSelector ps_selneg(ps_sel);
|
||||
|
||||
om_bselneg.negative = 1;
|
||||
ps_selneg.colclip = 2;
|
||||
|
||||
dev->SetupOM(om_dssel, om_bselneg, afix);
|
||||
dev->SetupPS(ps_selneg, &ps_cb, ps_ssel);
|
||||
|
||||
dev->DrawIndexedPrimitive();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dev->EndScene();
|
||||
|
||||
//OGL dev->Recycle(rtcopy);
|
||||
|
||||
if(om_dssel.fba) UpdateFBA(rt);
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (C) 2011-2011 Gregory hainaut
|
||||
* Copyright (C) 2007-2009 Gabest
|
||||
*
|
||||
* 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, 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSRendererHW.h"
|
||||
|
||||
#include "GSRenderer.h"
|
||||
#include "GSTextureCacheOGL.h"
|
||||
#include "GSVertexHW.h"
|
||||
|
||||
// FIXME does it need a GSVertexHWOGL ??? Data order can be easily programmed on opengl (the only potential
|
||||
// issue is the unsupported praga push/pop
|
||||
// Note it impact GSVertexTrace.cpp => void GSVertexTrace::Update(const GSVertexHWOGL* v, int count, GS_PRIM_CLASS primclass)
|
||||
class GSRendererOGL : public GSRendererHW
|
||||
//class GSRendererOGL : public GSRendererHW<GSVertexHWOGL>
|
||||
{
|
||||
private:
|
||||
GSVector2 m_pixelcenter;
|
||||
bool m_logz;
|
||||
bool m_fba;
|
||||
bool UserHacks_AlphaHack;
|
||||
int UserHacks_WildHack;
|
||||
|
||||
protected:
|
||||
void SetupIA();
|
||||
|
||||
public:
|
||||
GSRendererOGL();
|
||||
virtual ~GSRendererOGL() {};
|
||||
|
||||
bool CreateDevice(GSDevice* dev);
|
||||
|
||||
void UpdateFBA(GSTexture* rt) {}
|
||||
|
||||
void DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* tex);
|
||||
};
|
|
@ -21,6 +21,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
struct GSSetting
|
||||
{
|
||||
uint32 id;
|
||||
|
|
|
@ -35,7 +35,7 @@ protected:
|
|||
public:
|
||||
struct GSMap {uint8* bits; int pitch;};
|
||||
|
||||
enum {RenderTarget = 1, DepthStencil, Texture, Offscreen};
|
||||
enum {RenderTarget = 1, DepthStencil, Texture, Offscreen, Backbuffer};
|
||||
|
||||
public:
|
||||
GSTexture();
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright (C) 2011-2011 Gregory hainaut
|
||||
* Copyright (C) 2007-2009 Gabest
|
||||
* http://www.gabest.org
|
||||
*
|
||||
* 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, 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "GSTextureCacheOGL.h"
|
||||
|
||||
GSTextureCacheOGL::GSTextureCacheOGL(GSRenderer* r)
|
||||
: GSTextureCache(r)
|
||||
{
|
||||
}
|
||||
|
||||
void GSTextureCacheOGL::Read(Target* t, const GSVector4i& r)
|
||||
{
|
||||
if(t->m_type != RenderTarget)
|
||||
{
|
||||
assert(0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const GIFRegTEX0& TEX0 = t->m_TEX0;
|
||||
|
||||
if(TEX0.PSM != PSM_PSMCT32
|
||||
&& TEX0.PSM != PSM_PSMCT24
|
||||
&& TEX0.PSM != PSM_PSMCT16
|
||||
&& TEX0.PSM != PSM_PSMCT16S)
|
||||
{
|
||||
//ASSERT(0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(!t->m_dirty.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// printf("GSRenderTarget::Read %d,%d - %d,%d (%08x)\n", r.left, r.top, r.right, r.bottom, TEX0.TBP0);
|
||||
|
||||
int w = r.width();
|
||||
int h = r.height();
|
||||
|
||||
GSVector4 src = GSVector4(r) * GSVector4(t->m_texture->GetScale()).xyxy() / GSVector4(t->m_texture->GetSize()).xyxy();
|
||||
|
||||
GLuint format = TEX0.PSM == PSM_PSMCT16 || TEX0.PSM == PSM_PSMCT16S ? GL_R16UI : GL_RGBA8;
|
||||
//if (format == GL_R16UI) fprintf(stderr, "Format 16 bits integer\n");
|
||||
#if 0
|
||||
DXGI_FORMAT format = TEX0.PSM == PSM_PSMCT16 || TEX0.PSM == PSM_PSMCT16S ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
#endif
|
||||
|
||||
if(GSTexture* offscreen = m_renderer->m_dev->CopyOffscreen(t->m_texture, src, w, h, format))
|
||||
{
|
||||
GSTexture::GSMap m;
|
||||
|
||||
if(offscreen->Map(m))
|
||||
{
|
||||
// TODO: block level write
|
||||
|
||||
GSOffset* o = m_renderer->m_mem.GetOffset(TEX0.TBP0, TEX0.TBW, TEX0.PSM);
|
||||
|
||||
switch(TEX0.PSM)
|
||||
{
|
||||
case PSM_PSMCT32:
|
||||
m_renderer->m_mem.WritePixel32(m.bits, m.pitch, o, r);
|
||||
break;
|
||||
case PSM_PSMCT24:
|
||||
m_renderer->m_mem.WritePixel24(m.bits, m.pitch, o, r);
|
||||
break;
|
||||
case PSM_PSMCT16:
|
||||
case PSM_PSMCT16S:
|
||||
m_renderer->m_mem.WritePixel16(m.bits, m.pitch, o, r);
|
||||
break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
offscreen->Unmap();
|
||||
}
|
||||
|
||||
m_renderer->m_dev->Recycle(offscreen);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (C) 2011-2011 Gregory hainaut
|
||||
* Copyright (C) 2007-2009 Gabest
|
||||
* http://www.gabest.org
|
||||
*
|
||||
* 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, 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSTextureCache.h"
|
||||
#include "GSDeviceOGL.h"
|
||||
|
||||
class GSTextureCacheOGL : public GSTextureCache
|
||||
{
|
||||
protected:
|
||||
int Get8bitFormat() { return GL_R8; /* TODO return DXGI_FORMAT_A8_UNORM;*/}
|
||||
|
||||
void Read(Target* t, const GSVector4i& r);
|
||||
|
||||
public:
|
||||
GSTextureCacheOGL(GSRenderer* r);
|
||||
};
|
|
@ -0,0 +1,334 @@
|
|||
/*
|
||||
* Copyright (C) 2011-2011 Gregory hainaut
|
||||
* Copyright (C) 2007-2009 Gabest
|
||||
*
|
||||
* 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, 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "GSDeviceOGL.h"
|
||||
#include "GSTables.h"
|
||||
|
||||
void GSDeviceOGL::CreateTextureFX()
|
||||
{
|
||||
m_vs_cb = new GSUniformBufferOGL(4, sizeof(VSConstantBuffer));
|
||||
m_ps_cb = new GSUniformBufferOGL(5, sizeof(PSConstantBuffer));
|
||||
|
||||
glGenSamplers(1, &m_rt_ss);
|
||||
// FIXME, seem to have no difference between sampler !!!
|
||||
m_palette_ss = m_rt_ss;
|
||||
|
||||
glSamplerParameteri(m_rt_ss, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glSamplerParameteri(m_rt_ss, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glSamplerParameteri(m_rt_ss, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(m_rt_ss, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(m_rt_ss, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
// FIXME which value for GL_TEXTURE_MIN_LOD
|
||||
glSamplerParameteri(m_rt_ss, GL_TEXTURE_MAX_LOD, FLT_MAX);
|
||||
// FIXME: seems there is 2 possibility in opengl
|
||||
// DX: sd.ComparisonFunc = D3D11_COMPARISON_NEVER;
|
||||
// glSamplerParameteri(m_rt_ss, GL_TEXTURE_COMPARE_MODE, GL_NONE);
|
||||
glSamplerParameteri(m_rt_ss, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
|
||||
glSamplerParameteri(m_rt_ss, GL_TEXTURE_COMPARE_FUNC, GL_NEVER);
|
||||
// FIXME: need ogl extension sd.MaxAnisotropy = 16;
|
||||
|
||||
//{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
|
||||
//{"TEXCOORD", 1, DXGI_FORMAT_R32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
|
||||
//float2 t : TEXCOORD0;
|
||||
//float q : TEXCOORD1;
|
||||
//
|
||||
//{"POSITION", 0, DXGI_FORMAT_R16G16_UINT, 0, 16, D3D11_INPUT_PER_VERTEX_DATA, 0},
|
||||
//{"POSITION", 1, DXGI_FORMAT_R32_UINT, 0, 20, D3D11_INPUT_PER_VERTEX_DATA, 0},
|
||||
//uint2 p : POSITION0;
|
||||
//uint z : POSITION1;
|
||||
//
|
||||
//{"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0},
|
||||
//{"COLOR", 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0},
|
||||
//float4 c : COLOR0;
|
||||
//float4 f : COLOR1;
|
||||
|
||||
GSInputLayoutOGL vert_format[] =
|
||||
{
|
||||
// FIXME
|
||||
{0 , 2 , GL_FLOAT , GL_FALSE , sizeof(GSVertex) , (const GLvoid*)(0) } ,
|
||||
{1 , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof(GSVertex) , (const GLvoid*)(8) } ,
|
||||
{2 , 1 , GL_FLOAT , GL_FALSE , sizeof(GSVertex) , (const GLvoid*)(12) } ,
|
||||
{3 , 2 , GL_UNSIGNED_SHORT , GL_FALSE , sizeof(GSVertex) , (const GLvoid*)(16) } ,
|
||||
{4 , 1 , GL_UNSIGNED_INT , GL_FALSE , sizeof(GSVertex) , (const GLvoid*)(20) } ,
|
||||
// note: there is a 32 bits pad
|
||||
{5 , 2 , GL_UNSIGNED_SHORT , GL_FALSE , sizeof(GSVertex) , (const GLvoid*)(24) } ,
|
||||
{6 , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof(GSVertex) , (const GLvoid*)(28) } ,
|
||||
};
|
||||
m_vb = new GSVertexBufferStateOGL(sizeof(GSVertex), vert_format, countof(vert_format));
|
||||
}
|
||||
|
||||
void GSDeviceOGL::SetupVS(VSSelector sel, const VSConstantBuffer* cb)
|
||||
{
|
||||
// *************************************************************
|
||||
// Static
|
||||
// *************************************************************
|
||||
auto i = m_vs.find(sel);
|
||||
|
||||
if(i == m_vs.end())
|
||||
{
|
||||
std::string macro = format("#define VS_BPPZ %d\n", sel.bppz)
|
||||
+ format("#define VS_TME %d\n", sel.tme)
|
||||
+ format("#define VS_FST %d\n", sel.fst)
|
||||
+ format("#define VS_RTCOPY %d\n", sel.rtcopy);
|
||||
|
||||
GLuint vs;
|
||||
CompileShaderFromSource("tfx.glsl", "vs_main", GL_VERTEX_SHADER, &vs, macro);
|
||||
|
||||
m_vs[sel] = vs;
|
||||
i = m_vs.find(sel);
|
||||
}
|
||||
|
||||
// *************************************************************
|
||||
// Dynamic
|
||||
// *************************************************************
|
||||
if(m_vs_cb_cache.Update(cb)) {
|
||||
SetUniformBuffer(m_vs_cb);
|
||||
m_vs_cb->upload(cb);
|
||||
}
|
||||
|
||||
VSSetShader(i->second);
|
||||
}
|
||||
|
||||
void GSDeviceOGL::SetupGS(GSSelector sel)
|
||||
{
|
||||
// *************************************************************
|
||||
// Static
|
||||
// *************************************************************
|
||||
GLuint gs = 0;
|
||||
#ifdef AMD_DRIVER_WORKAROUND
|
||||
if (true)
|
||||
#else
|
||||
if(sel.prim > 0 && (sel.iip == 0 || sel.prim == 3))
|
||||
#endif
|
||||
{
|
||||
auto i = m_gs.find(sel);
|
||||
|
||||
if(i == m_gs.end()) {
|
||||
std::string macro = format("#define GS_IIP %d\n", sel.iip)
|
||||
+ format("#define GS_PRIM %d\n", sel.prim);
|
||||
|
||||
CompileShaderFromSource("tfx.glsl", "gs_main", GL_GEOMETRY_SHADER, &gs, macro);
|
||||
|
||||
m_gs[sel] = gs;
|
||||
} else {
|
||||
gs = i->second;
|
||||
}
|
||||
}
|
||||
// *************************************************************
|
||||
// Dynamic
|
||||
// *************************************************************
|
||||
GSSetShader(gs);
|
||||
}
|
||||
|
||||
void GSDeviceOGL::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel)
|
||||
{
|
||||
// *************************************************************
|
||||
// Static
|
||||
// *************************************************************
|
||||
GLuint ps;
|
||||
auto i = m_ps.find(sel);
|
||||
|
||||
if (i == m_ps.end())
|
||||
{
|
||||
std::string macro = format("#define PS_FST %d\n", sel.fst)
|
||||
+ format("#define PS_WMS %d\n", sel.wms)
|
||||
+ format("#define PS_WMT %d\n", sel.wmt)
|
||||
+ format("#define PS_FMT %d\n", sel.fmt)
|
||||
+ format("#define PS_AEM %d\n", sel.aem)
|
||||
+ format("#define PS_TFX %d\n", sel.tfx)
|
||||
+ format("#define PS_TCC %d\n", sel.tcc)
|
||||
+ format("#define PS_ATST %d\n", sel.atst)
|
||||
+ format("#define PS_FOG %d\n", sel.fog)
|
||||
+ format("#define PS_CLR1 %d\n", sel.clr1)
|
||||
+ format("#define PS_FBA %d\n", sel.fba)
|
||||
+ format("#define PS_AOUT %d\n", sel.aout)
|
||||
+ format("#define PS_LTF %d\n", sel.ltf)
|
||||
+ format("#define PS_COLCLIP %d\n", sel.colclip)
|
||||
+ format("#define PS_DATE %d\n", sel.date)
|
||||
+ format("#define PS_SPRITEHACK %d\n", sel.spritehack);
|
||||
|
||||
CompileShaderFromSource("tfx.glsl", "ps_main", GL_FRAGMENT_SHADER, &ps, macro);
|
||||
|
||||
m_ps[sel] = ps;
|
||||
i = m_ps.find(sel);
|
||||
} else {
|
||||
ps = i->second;
|
||||
}
|
||||
|
||||
// *************************************************************
|
||||
// Dynamic
|
||||
// *************************************************************
|
||||
if(m_ps_cb_cache.Update(cb)) {
|
||||
SetUniformBuffer(m_ps_cb);
|
||||
m_ps_cb->upload(cb);
|
||||
}
|
||||
|
||||
GLuint ss0, ss1;
|
||||
ss0 = ss1 = 0;
|
||||
if(sel.tfx != 4)
|
||||
{
|
||||
if(!(sel.fmt < 3 && sel.wms < 3 && sel.wmt < 3))
|
||||
{
|
||||
ssel.ltf = 0;
|
||||
}
|
||||
|
||||
auto i = m_ps_ss.find(ssel);
|
||||
|
||||
if(i != m_ps_ss.end())
|
||||
{
|
||||
ss0 = i->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
// *************************************************************
|
||||
// Static
|
||||
// *************************************************************
|
||||
glGenSamplers(1, &ss0);
|
||||
if (ssel.ltf) {
|
||||
glSamplerParameteri(ss0, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(ss0, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
} else {
|
||||
glSamplerParameteri(ss0, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glSamplerParameteri(ss0, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
|
||||
// FIXME ensure U -> S, V -> T and W->R
|
||||
if (ssel.tau)
|
||||
glSamplerParameteri(ss0, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
else
|
||||
glSamplerParameteri(ss0, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
|
||||
if (ssel.tav)
|
||||
glSamplerParameteri(ss0, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
else
|
||||
glSamplerParameteri(ss0, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
glSamplerParameteri(ss0, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
|
||||
// FIXME which value for GL_TEXTURE_MIN_LOD
|
||||
glSamplerParameteri(m_rt_ss, GL_TEXTURE_MAX_LOD, FLT_MAX);
|
||||
// FIXME: seems there is 2 possibility in opengl
|
||||
// DX: sd.ComparisonFunc = D3D11_COMPARISON_NEVER;
|
||||
// glSamplerParameteri(m_rt_ss, GL_TEXTURE_COMPARE_MODE, GL_NONE);
|
||||
glSamplerParameteri(m_rt_ss, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
|
||||
glSamplerParameteri(m_rt_ss, GL_TEXTURE_COMPARE_FUNC, GL_NEVER);
|
||||
// FIXME: need ogl extension sd.MaxAnisotropy = 16;
|
||||
|
||||
m_ps_ss[ssel] = ss0;
|
||||
}
|
||||
|
||||
if(sel.fmt >= 3)
|
||||
{
|
||||
ss1 = m_palette_ss;
|
||||
}
|
||||
}
|
||||
|
||||
PSSetSamplerState(ss0, ss1, sel.date ? m_rt_ss : 0);
|
||||
|
||||
PSSetShader(ps);
|
||||
}
|
||||
|
||||
void GSDeviceOGL::SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, uint8 afix)
|
||||
{
|
||||
auto i = m_om_dss.find(dssel);
|
||||
|
||||
// *************************************************************
|
||||
// Static
|
||||
// *************************************************************
|
||||
if (i == m_om_dss.end())
|
||||
{
|
||||
GSDepthStencilOGL* dss = new GSDepthStencilOGL();
|
||||
|
||||
if (dssel.date)
|
||||
{
|
||||
dss->EnableStencil();
|
||||
dss->SetStencil(GL_EQUAL, GL_KEEP);
|
||||
}
|
||||
|
||||
if(dssel.ztst != ZTST_ALWAYS || dssel.zwe)
|
||||
{
|
||||
static const GLenum ztst[] =
|
||||
{
|
||||
GL_NEVER,
|
||||
GL_ALWAYS,
|
||||
GL_GEQUAL,
|
||||
GL_GREATER
|
||||
};
|
||||
dss->EnableDepth();
|
||||
dss->SetDepth(ztst[dssel.ztst], dssel.zwe);
|
||||
}
|
||||
|
||||
m_om_dss[dssel] = dss;
|
||||
i = m_om_dss.find(dssel);
|
||||
}
|
||||
|
||||
// *************************************************************
|
||||
// Dynamic
|
||||
// *************************************************************
|
||||
OMSetDepthStencilState(i->second, 1);
|
||||
|
||||
// *************************************************************
|
||||
// Static
|
||||
// *************************************************************
|
||||
auto j = m_om_bs.find(bsel);
|
||||
|
||||
if(j == m_om_bs.end())
|
||||
{
|
||||
GSBlendStateOGL* bs = new GSBlendStateOGL();
|
||||
|
||||
if(bsel.abe)
|
||||
{
|
||||
int i = ((bsel.a * 3 + bsel.b) * 3 + bsel.c) * 3 + bsel.d;
|
||||
|
||||
bs->EnableBlend();
|
||||
bs->SetRGB(m_blendMapD3D9[i].op, m_blendMapD3D9[i].src, m_blendMapD3D9[i].dst);
|
||||
|
||||
if(m_blendMapD3D9[i].bogus == 1)
|
||||
{
|
||||
if (bsel.a == 0)
|
||||
bs->SetRGB(m_blendMapD3D9[i].op, GL_ONE, m_blendMapD3D9[i].dst);
|
||||
else
|
||||
bs->SetRGB(m_blendMapD3D9[i].op, m_blendMapD3D9[i].src, GL_ONE);
|
||||
|
||||
const string afixstr = format("%d >> 7", afix);
|
||||
const char *col[3] = {"Cs", "Cd", "0"};
|
||||
const char *alpha[3] = {"As", "Ad", afixstr.c_str()};
|
||||
|
||||
// FIXME, need to investigate OGL capabilities. Maybe for OGL5 ;)
|
||||
fprintf(stderr, "Impossible blend for D3D: (%s - %s) * %s + %s\n", col[bsel.a], col[bsel.b], alpha[bsel.c], col[bsel.d]);
|
||||
}
|
||||
|
||||
// Not very good but I don't wanna write another 81 row table
|
||||
if(bsel.negative) bs->RevertOp();
|
||||
}
|
||||
|
||||
bs->SetMask(bsel.wr, bsel.wg, bsel.wb, bsel.wa);
|
||||
|
||||
m_om_bs[bsel] = bs;
|
||||
j = m_om_bs.find(bsel);
|
||||
}
|
||||
|
||||
// *************************************************************
|
||||
// Dynamic
|
||||
// *************************************************************
|
||||
OMSetBlendState(j->second, (float)(int)afix / 0x80);
|
||||
}
|
|
@ -0,0 +1,448 @@
|
|||
/*
|
||||
* Copyright (C) 2011-2011 Gregory hainaut
|
||||
* Copyright (C) 2007-2009 Gabest
|
||||
*
|
||||
* 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, 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSTextureOGL.h"
|
||||
static int g_state_texture_unit = -1;
|
||||
static int g_state_texture_id = -1;
|
||||
|
||||
GSTextureOGL::GSTextureOGL(int type, int w, int h, bool msaa, int format, GLuint fbo_read)
|
||||
: m_pbo_id(0),
|
||||
m_pbo_size(0)
|
||||
{
|
||||
// *************************************************************
|
||||
// Opengl world
|
||||
|
||||
// Render work in parallal with framebuffer object (FBO) http://www.opengl.org/wiki/Framebuffer_Objects
|
||||
// render are attached to FBO through : glFramebufferRenderbuffer. You can query the number of colorattachement with GL_MAX_COLOR_ATTACHMENTS
|
||||
// FBO : constructor -> glGenFramebuffers, glDeleteFramebuffers
|
||||
// binding -> glBindFramebuffer (target can be read/write/both)
|
||||
// blit -> glBlitFramebuffer (read FB to draw FB)
|
||||
// info -> glIsFramebuffer, glGetFramebufferAttachmentParameter, glCheckFramebufferStatus
|
||||
//
|
||||
// There are two types of framebuffer-attachable images; texture images and renderbuffer images.
|
||||
// If an image of a texture object is attached to a framebuffer, OpenGL performs "render to texture".
|
||||
// And if an image of a renderbuffer object is attached to a framebuffer, then OpenGL performs "offscreen rendering".
|
||||
// Blitting:
|
||||
// glDrawBuffers
|
||||
// glReadBuffer
|
||||
// glBlitFramebuffer
|
||||
|
||||
// *************************************************************
|
||||
// m_size.x = w;
|
||||
// m_size.y = h;
|
||||
// FIXME
|
||||
m_size.x = max(1,w);
|
||||
m_size.y = max(1,h);
|
||||
m_format = format;
|
||||
m_type = type;
|
||||
m_msaa = msaa;
|
||||
m_fbo_read = fbo_read;
|
||||
|
||||
// Generate the buffer
|
||||
switch (m_type) {
|
||||
case GSTexture::Offscreen:
|
||||
//FIXME I not sure we need a pixel buffer object. It seems more a texture
|
||||
// glGenBuffers(1, &m_texture_id);
|
||||
// m_texture_target = GL_PIXEL_UNPACK_BUFFER;
|
||||
// assert(0);
|
||||
// Note there is also a buffer texture!!!
|
||||
// http://www.opengl.org/wiki/Buffer_Texture
|
||||
// Note: in this case it must use in GLSL
|
||||
// gvec texelFetch(gsampler sampler, ivec texCoord, int lod[, int sample]);
|
||||
// corollary we can maybe use it for multisample stuff
|
||||
case GSTexture::Texture:
|
||||
case GSTexture::RenderTarget:
|
||||
case GSTexture::DepthStencil:
|
||||
glGenTextures(1, &m_texture_id);
|
||||
m_texture_target = GL_TEXTURE_2D;
|
||||
break;
|
||||
case GSTexture::Backbuffer:
|
||||
m_texture_target = 0;
|
||||
m_texture_id = 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// Extra buffer to handle various pixel transfer
|
||||
glGenBuffers(1, &m_pbo_id);
|
||||
|
||||
uint msaa_level;
|
||||
if (m_msaa) {
|
||||
// FIXME which level of MSAA
|
||||
msaa_level = 1;
|
||||
} else {
|
||||
msaa_level = 0;
|
||||
}
|
||||
|
||||
// Allocate the buffer
|
||||
switch (m_type) {
|
||||
case GSTexture::DepthStencil:
|
||||
EnableUnit(0);
|
||||
glTexImage2D(m_texture_target, 0, m_format, m_size.x, m_size.y, 0, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, NULL);
|
||||
break;
|
||||
|
||||
case GSTexture::Offscreen:
|
||||
// Allocate a pbo with the texture
|
||||
if (m_format == GL_RGBA8) m_pbo_size = m_size.x * m_size.y * 4;
|
||||
else if (m_format == GL_R16UI) m_pbo_size = m_size.x * m_size.y * 2;
|
||||
else {
|
||||
fprintf(stderr, "wrong texture pixel format :%x\n", m_format);
|
||||
assert(0); // TODO Later
|
||||
}
|
||||
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, m_pbo_id);
|
||||
glBufferData(GL_PIXEL_PACK_BUFFER, m_pbo_size, NULL, GL_STREAM_DRAW);
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
||||
|
||||
case GSTexture::RenderTarget:
|
||||
case GSTexture::Texture:
|
||||
// FIXME
|
||||
// Howto allocate the texture unit !!!
|
||||
// In worst case the HW renderer seems to use 3 texture unit
|
||||
// For the moment SW renderer only use 1 so don't bother
|
||||
EnableUnit(0);
|
||||
// Did we need to setup a default sampler of the texture now?
|
||||
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
if (m_format == GL_RGBA8)
|
||||
glTexImage2D(m_texture_target, 0, m_format, m_size.x, m_size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
else if (m_format == GL_R16UI)
|
||||
glTexImage2D(m_texture_target, 0, m_format, m_size.x, m_size.y, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, NULL);
|
||||
else if (m_format == GL_R8)
|
||||
glTexImage2D(m_texture_target, 0, m_format, m_size.x, m_size.y, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
|
||||
else {
|
||||
fprintf(stderr, "wrong texture pixel format :%x\n", m_format);
|
||||
assert(0); // TODO Later
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
GSTextureOGL::~GSTextureOGL()
|
||||
{
|
||||
glDeleteBuffers(1, &m_pbo_id);
|
||||
glDeleteTextures(1, &m_texture_id);
|
||||
}
|
||||
|
||||
void GSTextureOGL::Attach(GLenum attachment)
|
||||
{
|
||||
//fprintf(stderr, "format %d,%x\n", m_type, m_format);
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment, m_texture_target, m_texture_id, 0);
|
||||
// FIXME DEBUG
|
||||
//fprintf(stderr, "FB status %x\n", glCheckFramebufferStatus(GL_FRAMEBUFFER));
|
||||
}
|
||||
|
||||
bool GSTextureOGL::Update(const GSVector4i& r, const void* data, int pitch)
|
||||
{
|
||||
if (m_type == GSTexture::DepthStencil || m_type == GSTexture::Offscreen) assert(0);
|
||||
|
||||
// FIXME warning order of the y axis
|
||||
// FIXME I'm not confident with GL_UNSIGNED_BYTE type
|
||||
|
||||
EnableUnit(0);
|
||||
|
||||
// pitch could be different of width*element_size
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch>>2);
|
||||
// FIXME : it crash on colin mcrae rally 3 (others game too) when the size is 16
|
||||
//fprintf(stderr, "Texture %dx%d with a pitch of %d\n", m_size.x, m_size.y, pitch >>2);
|
||||
//fprintf(stderr, "Box (%d,%d)x(%d,%d)\n", r.x, r.y, r.width(), r.height());
|
||||
|
||||
if (m_format == GL_RGBA8)
|
||||
glTexSubImage2D(m_texture_target, 0, r.x, r.y, r.width(), r.height(), GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
else if (m_format == GL_R16UI)
|
||||
glTexSubImage2D(m_texture_target, 0, r.x, r.y, r.width(), r.height(), GL_RED_INTEGER, GL_R16UI, data);
|
||||
else if (m_format == GL_R8)
|
||||
glTexSubImage2D(m_texture_target, 0, r.x, r.y, r.width(), r.height(), GL_RED, GL_R8, data);
|
||||
else {
|
||||
fprintf(stderr, "wrong texture pixel format :%x\n", m_format);
|
||||
assert(0);
|
||||
}
|
||||
#if 0
|
||||
//if (m_size.x != 16)
|
||||
if (r.width() > 16 && r.height() > 16)
|
||||
glTexSubImage2D(m_texture_target, 0, r.x, r.y, r.width(), r.height(), GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
else {
|
||||
fprintf(stderr, "skip texture upload\n");
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); // Restore default behavior
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); // Restore default behavior
|
||||
|
||||
return true;
|
||||
#if 0
|
||||
if(m_dev && m_texture)
|
||||
{
|
||||
D3D11_BOX box = {r.left, r.top, 0, r.right, r.bottom, 1};
|
||||
|
||||
m_ctx->UpdateSubresource(m_texture, 0, &box, data, pitch, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void GSTextureOGL::EnableUnit(uint unit)
|
||||
{
|
||||
if (!IsBackbuffer()) {
|
||||
// FIXME
|
||||
// Howto allocate the texture unit !!!
|
||||
// In worst case the HW renderer seems to use 3 texture unit
|
||||
// For the moment SW renderer only use 1 so don't bother
|
||||
if (g_state_texture_unit != unit) {
|
||||
g_state_texture_unit = unit;
|
||||
glActiveTexture(GL_TEXTURE0 + unit);
|
||||
// When you change the texture unit, texture must be rebinded
|
||||
g_state_texture_id = m_texture_id;
|
||||
glBindTexture(m_texture_target, m_texture_id);
|
||||
} else if (g_state_texture_id != m_texture_id) {
|
||||
g_state_texture_id = m_texture_id;
|
||||
glBindTexture(m_texture_target, m_texture_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GSTextureOGL::Map(GSMap& m, const GSVector4i* r)
|
||||
{
|
||||
// The function allow to modify the texture from the CPU
|
||||
// Set m.bits <- pointer to the data
|
||||
// Set m.pitch <- size of a row
|
||||
// I think in opengl we need to copy back the data to the RAM: glReadPixels — read a block of pixels from the frame buffer
|
||||
//
|
||||
// glMapBuffer — map a buffer object's data store
|
||||
// Can be used on GL_PIXEL_UNPACK_BUFFER or GL_TEXTURE_BUFFER
|
||||
if (m_type == GSTexture::Offscreen) {
|
||||
// Bind the texture to the read framebuffer to avoid any disturbance
|
||||
EnableUnit(0);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read);
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture_target, m_texture_id, 0);
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
||||
|
||||
// FIXME It might be possible to only read a subrange of the texture based on r object
|
||||
// Load the PBO with the data
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, m_pbo_id);
|
||||
if (m_format == GL_RGBA8) {
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 4);
|
||||
glReadPixels(0, 0, m_size.x, m_size.y, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||
} else if (m_format == GL_R16UI) {
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 2);
|
||||
glReadPixels(0, 0, m_size.x, m_size.y, GL_RED_INTEGER, GL_UNSIGNED_SHORT, 0);
|
||||
} else if (m_format == GL_R8) {
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glReadPixels(0, 0, m_size.x, m_size.y, GL_RED, GL_UNSIGNED_BYTE, 0);
|
||||
} else {
|
||||
fprintf(stderr, "wrong texture pixel format :%x\n", m_format);
|
||||
assert(0);
|
||||
}
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
|
||||
// Give access from the CPU
|
||||
m.bits = (uint8*) glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, m_pbo_size, GL_MAP_READ_BIT);
|
||||
m.pitch = m_size.x;
|
||||
|
||||
if ( m.bits ) {
|
||||
return true;
|
||||
} else {
|
||||
fprintf(stderr, "bad mapping of the pbo\n");
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
#if 0
|
||||
if(m_texture && m_desc.Usage == D3D11_USAGE_STAGING)
|
||||
{
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
|
||||
if(SUCCEEDED(m_ctx->Map(m_texture, 0, D3D11_MAP_READ_WRITE, 0, &map)))
|
||||
{
|
||||
m.bits = (uint8*)map.pData;
|
||||
m.pitch = (int)map.RowPitch;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void GSTextureOGL::Unmap()
|
||||
{
|
||||
if (m_type == GSTexture::Offscreen) {
|
||||
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef _WINDOWS
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct BITMAPFILEHEADER
|
||||
{
|
||||
uint16 bfType;
|
||||
uint32 bfSize;
|
||||
uint16 bfReserved1;
|
||||
uint16 bfReserved2;
|
||||
uint32 bfOffBits;
|
||||
};
|
||||
|
||||
struct BITMAPINFOHEADER
|
||||
{
|
||||
uint32 biSize;
|
||||
int32 biWidth;
|
||||
int32 biHeight;
|
||||
uint16 biPlanes;
|
||||
uint16 biBitCount;
|
||||
uint32 biCompression;
|
||||
uint32 biSizeImage;
|
||||
int32 biXPelsPerMeter;
|
||||
int32 biYPelsPerMeter;
|
||||
uint32 biClrUsed;
|
||||
uint32 biClrImportant;
|
||||
};
|
||||
|
||||
#define BI_RGB 0
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif
|
||||
void GSTextureOGL::Save(const string& fn, const void* image, uint32 pitch)
|
||||
{
|
||||
// Build a BMP file
|
||||
FILE* fp = fopen(fn.c_str(), "wb");
|
||||
|
||||
BITMAPINFOHEADER bih;
|
||||
|
||||
memset(&bih, 0, sizeof(bih));
|
||||
|
||||
bih.biSize = sizeof(bih);
|
||||
bih.biWidth = m_size.x;
|
||||
bih.biHeight = m_size.y;
|
||||
bih.biPlanes = 1;
|
||||
bih.biBitCount = 32;
|
||||
bih.biCompression = BI_RGB;
|
||||
bih.biSizeImage = m_size.x * m_size.y << 2;
|
||||
|
||||
BITMAPFILEHEADER bfh;
|
||||
|
||||
memset(&bfh, 0, sizeof(bfh));
|
||||
|
||||
uint8* bfType = (uint8*)&bfh.bfType;
|
||||
|
||||
// bfh.bfType = 'MB';
|
||||
bfType[0] = 0x42;
|
||||
bfType[1] = 0x4d;
|
||||
bfh.bfOffBits = sizeof(bfh) + sizeof(bih);
|
||||
bfh.bfSize = bfh.bfOffBits + bih.biSizeImage;
|
||||
bfh.bfReserved1 = bfh.bfReserved2 = 0;
|
||||
|
||||
fwrite(&bfh, 1, sizeof(bfh), fp);
|
||||
fwrite(&bih, 1, sizeof(bih), fp);
|
||||
|
||||
uint8* data = (uint8*)image + (m_size.y - 1) * pitch;
|
||||
|
||||
for(int h = m_size.y; h > 0; h--, data -= pitch)
|
||||
{
|
||||
if (IsDss()) {
|
||||
// Only get the depth and convert it to an integer
|
||||
uint8* better_data = data;
|
||||
for (int w = m_size.x; w > 0; w--, better_data += 8) {
|
||||
float* input = (float*)better_data;
|
||||
// FIXME how to dump 32 bits value into 8bits component color
|
||||
uint32 depth = (uint32)ldexpf(*input, 32);
|
||||
uint8 small_depth = depth >> 24;
|
||||
uint8 better_data[4] = {small_depth, small_depth, small_depth, 0 };
|
||||
fwrite(&better_data, 1, 4, fp);
|
||||
}
|
||||
} else {
|
||||
// swap red and blue
|
||||
uint8* better_data = data;
|
||||
for (int w = m_size.x; w > 0; w--, better_data += 4) {
|
||||
uint8 red = better_data[2];
|
||||
better_data[2] = better_data[0];
|
||||
better_data[0] = red;
|
||||
fwrite(better_data, 1, 4, fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
bool GSTextureOGL::Save(const string& fn, bool dds)
|
||||
{
|
||||
// Collect the texture data
|
||||
uint32 pitch = 4 * m_size.x;
|
||||
if (IsDss()) pitch *= 2;
|
||||
char* image = (char*)malloc(pitch * m_size.y);
|
||||
bool status = true;
|
||||
|
||||
// FIXME instead of swapping manually B and R maybe you can request the driver to do it
|
||||
// for us
|
||||
if (IsBackbuffer()) {
|
||||
//glReadBuffer(GL_BACK);
|
||||
//glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
glReadPixels(0, 0, m_size.x, m_size.y, GL_RGBA, GL_UNSIGNED_BYTE, image);
|
||||
} else if(IsDss()) {
|
||||
EnableUnit(0);
|
||||
glGetTexImage(m_texture_target, 0, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, image);
|
||||
} else {
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read);
|
||||
|
||||
EnableUnit(0);
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture_target, m_texture_id, 0);
|
||||
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
||||
if (m_format == GL_RGBA8)
|
||||
glReadPixels(0, 0, m_size.x, m_size.y, GL_RGBA, GL_UNSIGNED_BYTE, image);
|
||||
else if (m_format == GL_R16UI)
|
||||
{
|
||||
glReadPixels(0, 0, m_size.x, m_size.y, GL_RED_INTEGER, GL_UNSIGNED_SHORT, image);
|
||||
// Not supported in Save function
|
||||
status = false;
|
||||
}
|
||||
else if (m_format == GL_R8)
|
||||
{
|
||||
glReadPixels(0, 0, m_size.x, m_size.y, GL_RED, GL_UNSIGNED_BYTE, image);
|
||||
// Not supported in Save function
|
||||
status = false;
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
if (status) Save(fn, image, pitch);
|
||||
free(image);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (C) 2011-2011 Gregory hainaut
|
||||
* Copyright (C) 2007-2009 Gabest
|
||||
*
|
||||
* 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, 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSTexture.h"
|
||||
|
||||
class GSTextureOGL : public GSTexture
|
||||
{
|
||||
private:
|
||||
GLenum m_texture_target; // texture target: 2D, rectangle etc...
|
||||
GLuint m_texture_id; // the texture id
|
||||
uint m_pbo_id;
|
||||
int m_pbo_size;
|
||||
GLuint m_fbo_read;
|
||||
|
||||
public:
|
||||
explicit GSTextureOGL(int type, int w, int h, bool msaa, int format, GLuint fbo_read);
|
||||
virtual ~GSTextureOGL();
|
||||
|
||||
bool Update(const GSVector4i& r, const void* data, int pitch);
|
||||
bool Map(GSMap& m, const GSVector4i* r = NULL);
|
||||
void Unmap();
|
||||
bool Save(const string& fn, bool dds = false);
|
||||
void Save(const string& fn, const void* image, uint32 pitch);
|
||||
|
||||
void EnableUnit(uint unit);
|
||||
void Attach(GLenum attachment);
|
||||
|
||||
bool IsBackbuffer() { return (m_type == GSTexture::Backbuffer); }
|
||||
bool IsDss() { return (m_type == GSTexture::DepthStencil); }
|
||||
|
||||
GLuint GetID() { return m_texture_id; }
|
||||
GLenum GetTarget() { return m_texture_target; }
|
||||
};
|
|
@ -52,7 +52,7 @@ struct GSVertexP
|
|||
GSVector4 p;
|
||||
};
|
||||
|
||||
struct GSVertexPT1
|
||||
__aligned(struct, 32) GSVertexPT1
|
||||
{
|
||||
GSVector4 p;
|
||||
GSVector2 t;
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
{
|
||||
m_base = _aligned_malloc(sizeof(Vertex) * countof(m_v), 32);
|
||||
|
||||
for(int i = 0; i < countof(m_v); i++)
|
||||
for(uint i = 0; i < countof(m_v); i++)
|
||||
{
|
||||
m_v[i] = &((Vertex*)m_base)[i];
|
||||
}
|
||||
|
|
|
@ -212,105 +212,6 @@ void GSWnd::HideFrame()
|
|||
|
||||
#else
|
||||
|
||||
/*
|
||||
GSWnd::GSWnd()
|
||||
: m_display(NULL)
|
||||
, m_window(0)
|
||||
, m_managed(true)
|
||||
, m_frame(true)
|
||||
{
|
||||
}
|
||||
|
||||
GSWnd::~GSWnd()
|
||||
{
|
||||
if(m_display != NULL)
|
||||
{
|
||||
if(m_window != 0)
|
||||
{
|
||||
XDestroyWindow(m_display, m_window);
|
||||
}
|
||||
|
||||
XCloseDisplay(m_display);
|
||||
}
|
||||
}
|
||||
|
||||
bool GSWnd::Create(const string& title, int w, int h)
|
||||
{
|
||||
if(m_display != NULL) return false;
|
||||
|
||||
if(!XInitThreads()) return false;
|
||||
|
||||
m_display = XOpenDisplay(0);
|
||||
|
||||
if(m_display == NULL) return false;
|
||||
|
||||
m_window = XCreateSimpleWindow(m_display, RootWindow(m_display, 0), 0, 0, 640, 480, 0, BlackPixel(m_display, 0), BlackPixel(m_display, 0));
|
||||
|
||||
XFlush(m_display);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
GSVector4i GSWnd::GetClientRect()
|
||||
{
|
||||
int x, y;
|
||||
unsigned int w, h;
|
||||
unsigned int border, depth;
|
||||
Window root;
|
||||
|
||||
XLockDisplay(m_display);
|
||||
XGetGeometry(m_display, m_window, &root, &x, &y, &w, &h, &border, &depth);
|
||||
XUnlockDisplay(m_display);
|
||||
|
||||
return GSVector4i(0, 0, w, h);
|
||||
}
|
||||
|
||||
// Returns FALSE if the window has no title, or if th window title is under the strict
|
||||
// management of the emulator.
|
||||
|
||||
bool GSWnd::SetWindowText(const char* title)
|
||||
{
|
||||
if(!m_managed) return false;
|
||||
|
||||
XTextProperty p;
|
||||
|
||||
p.value = (unsigned char*)title;
|
||||
p.encoding = XA_STRING;
|
||||
p.format = 8;
|
||||
p.nitems = strlen(title);
|
||||
|
||||
XSetWMName(m_display, m_window, &p);
|
||||
XFlush(m_display);
|
||||
|
||||
return m_frame;
|
||||
}
|
||||
|
||||
void GSWnd::Show()
|
||||
{
|
||||
if(!m_managed) return;
|
||||
|
||||
XMapWindow(m_display, m_window);
|
||||
XFlush(m_display);
|
||||
}
|
||||
|
||||
void GSWnd::Hide()
|
||||
{
|
||||
if(!m_managed) return;
|
||||
|
||||
XUnmapWindow(m_display, m_window);
|
||||
XFlush(m_display);
|
||||
}
|
||||
|
||||
void GSWnd::HideFrame()
|
||||
{
|
||||
if(!m_managed) return;
|
||||
|
||||
// TODO
|
||||
|
||||
m_frame = false;
|
||||
}
|
||||
*/
|
||||
|
||||
GSWnd::GSWnd()
|
||||
: m_window(NULL), m_Xwindow(0), m_XDisplay(NULL)
|
||||
{
|
||||
|
@ -318,22 +219,104 @@ GSWnd::GSWnd()
|
|||
|
||||
GSWnd::~GSWnd()
|
||||
{
|
||||
#ifdef ENABLE_SDL_DEV
|
||||
if(m_window != NULL && m_managed)
|
||||
{
|
||||
SDL_DestroyWindow(m_window);
|
||||
m_window = NULL;
|
||||
}
|
||||
#endif
|
||||
if (m_XDisplay) {
|
||||
XCloseDisplay(m_XDisplay);
|
||||
m_XDisplay = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool GSWnd::CreateContext(int major, int minor)
|
||||
{
|
||||
if ( !m_XDisplay || !m_Xwindow )
|
||||
{
|
||||
fprintf( stderr, "Wrong X11 display/window\n" );
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Get visual information
|
||||
static int attrListDbl[] =
|
||||
{
|
||||
GLX_X_RENDERABLE , True,
|
||||
GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT,
|
||||
GLX_RENDER_TYPE , GLX_RGBA_BIT,
|
||||
GLX_RED_SIZE , 8,
|
||||
GLX_GREEN_SIZE , 8,
|
||||
GLX_BLUE_SIZE , 8,
|
||||
GLX_DEPTH_SIZE , 24,
|
||||
GLX_DOUBLEBUFFER , True,
|
||||
None
|
||||
};
|
||||
|
||||
PFNGLXCHOOSEFBCONFIGPROC glXChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC) glXGetProcAddress((GLubyte *) "glXChooseFBConfig");
|
||||
int fbcount = 0;
|
||||
GLXFBConfig *fbc = glXChooseFBConfig(m_XDisplay, DefaultScreen(m_XDisplay), attrListDbl, &fbcount);
|
||||
if (!fbc || fbcount < 1) return false;
|
||||
|
||||
PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((const GLubyte*) "glXCreateContextAttribsARB");
|
||||
if (!glXCreateContextAttribsARB) return false;
|
||||
|
||||
// Create a context
|
||||
int context_attribs[] =
|
||||
{
|
||||
GLX_CONTEXT_MAJOR_VERSION_ARB, major,
|
||||
GLX_CONTEXT_MINOR_VERSION_ARB, minor,
|
||||
// FIXME : Request a debug context to ease opengl development
|
||||
// Note: don't support deprecated feature (pre openg 3.1)
|
||||
//GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB | GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
|
||||
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB,
|
||||
None
|
||||
};
|
||||
|
||||
m_context = glXCreateContextAttribsARB(m_XDisplay, fbc[0], 0, true, context_attribs);
|
||||
if (!m_context) return false;
|
||||
|
||||
XSync( m_XDisplay, false);
|
||||
}
|
||||
|
||||
void GSWnd::AttachContext()
|
||||
{
|
||||
glXMakeCurrent(m_XDisplay, m_Xwindow, m_context);
|
||||
}
|
||||
|
||||
void GSWnd::DetachContext()
|
||||
{
|
||||
glXMakeCurrent(m_XDisplay, None, NULL);
|
||||
}
|
||||
|
||||
void GSWnd::CheckContext()
|
||||
{
|
||||
int glxMajorVersion, glxMinorVersion;
|
||||
glXQueryVersion(m_XDisplay, &glxMajorVersion, &glxMinorVersion);
|
||||
if (glXIsDirect(m_XDisplay, m_context))
|
||||
fprintf(stderr, "glX-Version %d.%d with Direct Rendering\n", glxMajorVersion, glxMinorVersion);
|
||||
else
|
||||
fprintf(stderr, "glX-Version %d.%d with Indirect Rendering !!! It will be slow\n", glxMajorVersion, glxMinorVersion);
|
||||
}
|
||||
|
||||
bool GSWnd::Attach(void* handle, bool managed)
|
||||
{
|
||||
m_Xwindow = *(Window*)handle;
|
||||
m_managed = managed;
|
||||
|
||||
m_renderer = theApp.GetConfig("renderer", 0) / 3;
|
||||
if (m_renderer != 2) {
|
||||
m_XDisplay = XOpenDisplay(NULL);
|
||||
|
||||
// Note: 4.2 crash on latest nvidia drivers!
|
||||
if (!CreateContext(3, 3)) return false;
|
||||
|
||||
AttachContext();
|
||||
|
||||
CheckContext();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -341,10 +324,17 @@ void GSWnd::Detach()
|
|||
{
|
||||
// Actually the destructor is not called when there is only a GSclose/GSshutdown
|
||||
// The window still need to be closed
|
||||
if(m_window != NULL && m_managed)
|
||||
{
|
||||
SDL_DestroyWindow(m_window);
|
||||
m_window = NULL;
|
||||
if (m_renderer == 2) {
|
||||
#ifdef ENABLE_SDL_DEV
|
||||
if(m_window != NULL && m_managed)
|
||||
{
|
||||
SDL_DestroyWindow(m_window);
|
||||
m_window = NULL;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
DetachContext();
|
||||
if (m_context) glXDestroyContext(m_XDisplay, m_context);
|
||||
}
|
||||
if (m_XDisplay) {
|
||||
XCloseDisplay(m_XDisplay);
|
||||
|
@ -361,40 +351,83 @@ bool GSWnd::Create(const string& title, int w, int h)
|
|||
h = theApp.GetConfig("ModeHeight", 480);
|
||||
}
|
||||
|
||||
#ifdef _LINUX
|
||||
// When you reconfigure the plugins during the play, SDL is shutdown so SDL_GetNumVideoDisplays return 0
|
||||
// and the plugins is badly closed. NOTE: SDL is initialized in SDL_CreateWindow.
|
||||
//
|
||||
// I'm not sure this sanity check is still useful, normally (I hope) SDL_CreateWindow will return a null
|
||||
// hence a false for this current function.
|
||||
// For the moment do an init -- Gregory
|
||||
if(!SDL_WasInit(SDL_INIT_VIDEO))
|
||||
if(SDL_Init(SDL_INIT_VIDEO) < 0) return false;
|
||||
m_managed = true;
|
||||
|
||||
// Sanity check; if there aren't any video displays available, we can't create a window.
|
||||
if (SDL_GetNumVideoDisplays() <= 0) return false;
|
||||
if (m_renderer == 2) {
|
||||
#ifdef ENABLE_SDL_DEV
|
||||
|
||||
#ifdef _LINUX
|
||||
// When you reconfigure the plugins during the play, SDL is shutdown so SDL_GetNumVideoDisplays return 0
|
||||
// and the plugins is badly closed. NOTE: SDL is initialized in SDL_CreateWindow.
|
||||
//
|
||||
// I'm not sure this sanity check is still useful, normally (I hope) SDL_CreateWindow will return a null
|
||||
// hence a false for this current function.
|
||||
// For the moment do an init -- Gregory
|
||||
if(!SDL_WasInit(SDL_INIT_VIDEO))
|
||||
if(SDL_Init(SDL_INIT_VIDEO) < 0) return false;
|
||||
|
||||
// Sanity check; if there aren't any video displays available, we can't create a window.
|
||||
if (SDL_GetNumVideoDisplays() <= 0) return false;
|
||||
#endif
|
||||
|
||||
m_managed = true;
|
||||
m_window = SDL_CreateWindow(title.c_str(), 100, 100, w, h, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
|
||||
m_window = SDL_CreateWindow(title.c_str(), 100, 100, w, h, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
|
||||
|
||||
// Get the X window from the newly created window
|
||||
// It would be needed to get the current size
|
||||
SDL_SysWMinfo wminfo;
|
||||
memset(&wminfo, 0, sizeof(wminfo));
|
||||
// Get the X window from the newly created window
|
||||
// It would be needed to get the current size
|
||||
SDL_SysWMinfo wminfo;
|
||||
memset(&wminfo, 0, sizeof(wminfo));
|
||||
|
||||
wminfo.version.major = SDL_MAJOR_VERSION;
|
||||
wminfo.version.minor = SDL_MINOR_VERSION;
|
||||
wminfo.version.major = SDL_MAJOR_VERSION;
|
||||
wminfo.version.minor = SDL_MINOR_VERSION;
|
||||
|
||||
SDL_GetWindowWMInfo(m_window, &wminfo);
|
||||
m_Xwindow = wminfo.info.x11.window;
|
||||
SDL_GetWindowWMInfo(m_window, &wminfo);
|
||||
m_Xwindow = wminfo.info.x11.window;
|
||||
|
||||
#endif
|
||||
return (m_window != NULL);
|
||||
|
||||
return (m_window != NULL);
|
||||
} else {
|
||||
|
||||
// note this part must be only executed when replaying .gs debug file
|
||||
m_XDisplay = XOpenDisplay(NULL);
|
||||
|
||||
int attrListDbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER,
|
||||
GLX_RED_SIZE, 8,
|
||||
GLX_GREEN_SIZE, 8,
|
||||
GLX_BLUE_SIZE, 8,
|
||||
GLX_DEPTH_SIZE, 24,
|
||||
None
|
||||
};
|
||||
XVisualInfo* vi = glXChooseVisual(m_XDisplay, DefaultScreen(m_XDisplay), attrListDbl);
|
||||
|
||||
/* create a color map */
|
||||
XSetWindowAttributes attr;
|
||||
attr.colormap = XCreateColormap(m_XDisplay, RootWindow(m_XDisplay, vi->screen),
|
||||
vi->visual, AllocNone);
|
||||
attr.border_pixel = 0;
|
||||
attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask |
|
||||
StructureNotifyMask | SubstructureRedirectMask | SubstructureNotifyMask |
|
||||
EnterWindowMask | LeaveWindowMask | FocusChangeMask ;
|
||||
|
||||
// Create a window at the last position/size
|
||||
m_Xwindow = XCreateWindow(m_XDisplay, RootWindow(m_XDisplay, vi->screen),
|
||||
0 , 0 , w, h, 0, vi->depth, InputOutput, vi->visual,
|
||||
CWBorderPixel | CWColormap | CWEventMask, &attr);
|
||||
|
||||
XMapWindow (m_XDisplay, m_Xwindow);
|
||||
XFree(vi);
|
||||
|
||||
if (!CreateContext(3, 3)) return false;
|
||||
|
||||
AttachContext();
|
||||
|
||||
return (m_Xwindow != 0);
|
||||
}
|
||||
}
|
||||
|
||||
Display* GSWnd::GetDisplay()
|
||||
{
|
||||
#ifdef ENABLE_SDL_DEV
|
||||
SDL_SysWMinfo wminfo;
|
||||
|
||||
memset(&wminfo, 0, sizeof(wminfo));
|
||||
|
@ -405,6 +438,10 @@ Display* GSWnd::GetDisplay()
|
|||
SDL_GetWindowWMInfo(m_window, &wminfo);
|
||||
|
||||
return wminfo.subsystem == SDL_SYSWM_X11 ? wminfo.info.x11.display : NULL;
|
||||
#else
|
||||
// note this part must be only executed when replaying .gs debug file
|
||||
return m_XDisplay;
|
||||
#endif
|
||||
}
|
||||
|
||||
GSVector4i GSWnd::GetClientRect()
|
||||
|
@ -425,7 +462,10 @@ GSVector4i GSWnd::GetClientRect()
|
|||
// In real world...:
|
||||
if (!m_XDisplay) m_XDisplay = XOpenDisplay(NULL);
|
||||
XGetGeometry(m_XDisplay, m_Xwindow, &winDummy, &xDummy, &yDummy, &w, &h, &borderDummy, &depthDummy);
|
||||
SDL_SetWindowSize(m_window, w, h);
|
||||
#ifdef ENABLE_SDL_DEV
|
||||
if (m_renderer == 2)
|
||||
SDL_SetWindowSize(m_window, w, h);
|
||||
#endif
|
||||
|
||||
return GSVector4i(0, 0, (int)w, (int)h);
|
||||
}
|
||||
|
@ -437,6 +477,9 @@ bool GSWnd::SetWindowText(const char* title)
|
|||
{
|
||||
if (!m_managed) return true;
|
||||
|
||||
if (m_renderer == 2) {
|
||||
#ifdef ENABLE_SDL_DEV
|
||||
|
||||
// Do not find anyway to check the current fullscreen status
|
||||
// Better than nothing heuristic, check the window position. Fullscreen = (0,0)
|
||||
// if(!(m_window->flags & SDL_WINDOW_FULLSCREEN) ) // Do not compile
|
||||
|
@ -445,23 +488,67 @@ bool GSWnd::SetWindowText(const char* title)
|
|||
// but we not use this function anyway.
|
||||
// FIXME: it does not feel a good solution -- Gregory
|
||||
// NOte: it might be more thread safe to use a call to XGetGeometry
|
||||
SDL_PumpEvents();
|
||||
int x,y = 0;
|
||||
SDL_GetWindowPosition(m_window, &x, &y);
|
||||
if ( x && y )
|
||||
SDL_SetWindowTitle(m_window, title);
|
||||
int x,y = 0;
|
||||
SDL_PumpEvents();
|
||||
SDL_GetWindowPosition(m_window, &x, &y);
|
||||
if ( x && y )
|
||||
SDL_SetWindowTitle(m_window, title);
|
||||
|
||||
#endif
|
||||
} else {
|
||||
XTextProperty prop;
|
||||
|
||||
memset(&prop, 0, sizeof(prop));
|
||||
|
||||
char* ptitle = (char*)title;
|
||||
if (XStringListToTextProperty(&ptitle, 1, &prop)) {
|
||||
XSetWMName(m_XDisplay, m_Xwindow, &prop);
|
||||
}
|
||||
|
||||
XFree(prop.value);
|
||||
XFlush(m_XDisplay);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GSWnd::Flip()
|
||||
{
|
||||
if (m_renderer == 2) {
|
||||
#ifdef ENABLE_SDL_DEV
|
||||
#if SDL_VERSION_ATLEAST(1,3,0)
|
||||
SDL_GL_SwapWindow(m_window);
|
||||
#else
|
||||
SDL_GL_SwapBuffers();
|
||||
#endif
|
||||
#endif
|
||||
} else {
|
||||
glXSwapBuffers(m_XDisplay, m_Xwindow);
|
||||
}
|
||||
}
|
||||
|
||||
void GSWnd::Show()
|
||||
{
|
||||
SDL_ShowWindow(m_window);
|
||||
if (m_renderer == 2) {
|
||||
#ifdef ENABLE_SDL_DEV
|
||||
SDL_ShowWindow(m_window);
|
||||
#endif
|
||||
} else {
|
||||
XMapRaised(m_XDisplay, m_Xwindow);
|
||||
XFlush(m_XDisplay);
|
||||
}
|
||||
}
|
||||
|
||||
void GSWnd::Hide()
|
||||
{
|
||||
SDL_HideWindow(m_window);
|
||||
if (m_renderer == 2) {
|
||||
#ifdef ENABLE_SDL_DEV
|
||||
SDL_HideWindow(m_window);
|
||||
#endif
|
||||
} else {
|
||||
XUnmapWindow(m_XDisplay, m_Xwindow);
|
||||
XFlush(m_XDisplay);
|
||||
}
|
||||
}
|
||||
|
||||
void GSWnd::HideFrame()
|
||||
|
|
|
@ -88,15 +88,24 @@ public:
|
|||
};
|
||||
*/
|
||||
#include <X11/Xlib.h>
|
||||
#ifdef ENABLE_SDL_DEV
|
||||
#include "../../3rdparty/SDL-1.3.0-5387/include/SDL.h"
|
||||
#include "../../3rdparty/SDL-1.3.0-5387/include/SDL_syswm.h"
|
||||
#endif
|
||||
|
||||
class GSWnd
|
||||
{
|
||||
#ifdef ENABLE_SDL_DEV
|
||||
SDL_Window* m_window;
|
||||
Window m_Xwindow;
|
||||
Display* m_XDisplay;
|
||||
#else
|
||||
void* m_window;
|
||||
#endif
|
||||
Window m_Xwindow;
|
||||
Display* m_XDisplay;
|
||||
|
||||
bool m_managed;
|
||||
int m_renderer;
|
||||
GLXContext m_context;
|
||||
|
||||
public:
|
||||
GSWnd();
|
||||
|
@ -111,11 +120,19 @@ public:
|
|||
void* GetHandle() {return (void*)m_Xwindow;}
|
||||
GSVector4i GetClientRect();
|
||||
bool SetWindowText(const char* title);
|
||||
#ifdef ENABLE_SDL_DEV
|
||||
void SetWindow(SDL_Window* current_window) { if (current_window) m_window = current_window; }
|
||||
#endif
|
||||
|
||||
bool CreateContext(int major, int minor);
|
||||
void AttachContext();
|
||||
void DetachContext();
|
||||
void CheckContext();
|
||||
|
||||
void Show();
|
||||
void Hide();
|
||||
void HideFrame();
|
||||
void Flip();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -116,6 +116,8 @@ GSdxApp::GSdxApp()
|
|||
m_gs_renderers.push_back(GSSetting(8, "SDL 1.3", "Null"));
|
||||
m_gs_renderers.push_back(GSSetting(10, "Null", "Software"));
|
||||
m_gs_renderers.push_back(GSSetting(11, "Null", "Null"));
|
||||
m_gs_renderers.push_back(GSSetting(12, "OpenGL", "Hardware"));
|
||||
m_gs_renderers.push_back(GSSetting(13, "OpenGL", "Software"));
|
||||
|
||||
m_gs_interlace.push_back(GSSetting(0, "None", ""));
|
||||
m_gs_interlace.push_back(GSSetting(1, "Weave tff", "saw-tooth"));
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (C) 20011-2012 Hainaut gregory
|
||||
*
|
||||
* 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, 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
EXPORT_C GSsetSettingsDir(const char* dir);
|
||||
EXPORT_C GSReplay(char* lpszCmdLine, int renderer);
|
||||
|
||||
|
||||
void help()
|
||||
{
|
||||
fprintf(stderr, "Loader gs file\n");
|
||||
fprintf(stderr, "ARG1 Ini directory\n");
|
||||
fprintf(stderr, "ARG2 .gs file\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main ( int argc, char *argv[] )
|
||||
{
|
||||
if ( argc != 3 ) help();
|
||||
|
||||
GSsetSettingsDir(argv[1]);
|
||||
GSReplay(argv[2], 12);
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
//#version 420 // Keep it for editor detection
|
||||
|
||||
struct vertex_basic
|
||||
{
|
||||
vec4 p;
|
||||
vec2 t;
|
||||
};
|
||||
|
||||
|
||||
#ifdef VERTEX_SHADER
|
||||
|
||||
out gl_PerVertex {
|
||||
vec4 gl_Position;
|
||||
float gl_PointSize;
|
||||
float gl_ClipDistance[];
|
||||
};
|
||||
|
||||
layout(location = 0) in vec4 POSITION;
|
||||
layout(location = 1) in vec2 TEXCOORD0;
|
||||
|
||||
// FIXME set the interpolation (don't know what dx do)
|
||||
// flat means that there is no interpolation. The value given to the fragment shader is based on the provoking vertex conventions.
|
||||
//
|
||||
// noperspective means that there will be linear interpolation in window-space. This is usually not what you want, but it can have its uses.
|
||||
//
|
||||
// smooth, the default, means to do perspective-correct interpolation.
|
||||
//
|
||||
// The centroid qualifier only matters when multisampling. If this qualifier is not present, then the value is interpolated to the pixel's center, anywhere in the pixel, or to one of the pixel's samples. This sample may lie outside of the actual primitive being rendered, since a primitive can cover only part of a pixel's area. The centroid qualifier is used to prevent this; the interpolation point must fall within both the pixel's area and the primitive's area.
|
||||
layout(location = 0) out vertex_basic VSout;
|
||||
|
||||
void vs_main()
|
||||
{
|
||||
VSout.p = POSITION;
|
||||
VSout.t = TEXCOORD0;
|
||||
gl_Position = POSITION; // NOTE I don't know if it is possible to merge POSITION_OUT and gl_Position
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef GEOMETRY_SHADER
|
||||
in gl_PerVertex {
|
||||
vec4 gl_Position;
|
||||
float gl_PointSize;
|
||||
float gl_ClipDistance[];
|
||||
} gl_in[];
|
||||
|
||||
out gl_PerVertex {
|
||||
vec4 gl_Position;
|
||||
float gl_PointSize;
|
||||
float gl_ClipDistance[];
|
||||
};
|
||||
|
||||
// FIXME
|
||||
// AMD Driver bug again !!!!
|
||||
//layout(location = 0) in vertex GSin[];
|
||||
in vertex_basic GSin[];
|
||||
|
||||
layout(location = 0) out vertex_basic GSout;
|
||||
layout(triangles) in;
|
||||
layout(triangle_strip, max_vertices = 3) out;
|
||||
|
||||
void gs_main()
|
||||
{
|
||||
for(int i = 0; i < gl_in.length(); i++) {
|
||||
gl_Position = gl_in[i].gl_Position;
|
||||
GSout = GSin[i];
|
||||
EmitVertex();
|
||||
}
|
||||
EndPrimitive();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FRAGMENT_SHADER
|
||||
// NOTE: pixel can be clip with "discard"
|
||||
|
||||
layout(location = 0) in vertex_basic PSin;
|
||||
|
||||
layout(location = 0) out vec4 SV_Target0;
|
||||
layout(location = 1) out uint SV_Target1;
|
||||
|
||||
layout(binding = 0) uniform sampler2D TextureSampler;
|
||||
|
||||
vec4 sample_c()
|
||||
{
|
||||
return texture(TextureSampler, PSin.t );
|
||||
}
|
||||
|
||||
vec4 ps_crt(uint i)
|
||||
{
|
||||
vec4 mask[4] =
|
||||
{
|
||||
vec4(1, 0, 0, 0),
|
||||
vec4(0, 1, 0, 0),
|
||||
vec4(0, 0, 1, 0),
|
||||
vec4(1, 1, 1, 0)
|
||||
};
|
||||
|
||||
return sample_c() * clamp((mask[i] + 0.5f), 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
void ps_main0()
|
||||
{
|
||||
SV_Target0 = sample_c();
|
||||
}
|
||||
|
||||
void ps_main1()
|
||||
{
|
||||
vec4 c = sample_c();
|
||||
|
||||
c.a *= 256.0f / 127.0f; // hm, 0.5 won't give us 1.0 if we just multiply with 2
|
||||
|
||||
highp uvec4 i = uvec4(c * vec4(0x001f, 0x03e0, 0x7c00, 0x8000));
|
||||
|
||||
SV_Target1 = (i.x & uint(0x001f)) | (i.y & uint(0x03e0)) | (i.z & uint(0x7c00)) | (i.w & uint(0x8000));
|
||||
}
|
||||
|
||||
void ps_main7()
|
||||
{
|
||||
vec4 c = sample_c();
|
||||
|
||||
c.a = dot(c.rgb, vec3(0.299, 0.587, 0.114));
|
||||
|
||||
SV_Target0 = c;
|
||||
}
|
||||
|
||||
void ps_main5() // triangular
|
||||
{
|
||||
highp uvec4 p = uvec4(PSin.p);
|
||||
|
||||
vec4 c = ps_crt(((p.x + ((p.y >> 1u) & 1u) * 3u) >> 1u) % 3u);
|
||||
|
||||
SV_Target0 = c;
|
||||
}
|
||||
|
||||
void ps_main6() // diagonal
|
||||
{
|
||||
uvec4 p = uvec4(PSin.p);
|
||||
|
||||
vec4 c = ps_crt((p.x + (p.y % 3u)) % 3u);
|
||||
|
||||
SV_Target0 = c;
|
||||
}
|
||||
|
||||
void ps_main2()
|
||||
{
|
||||
if((sample_c().a - 128.0f / 255) < 0) // >= 0x80 pass
|
||||
discard;
|
||||
|
||||
SV_Target0 = vec4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
void ps_main3()
|
||||
{
|
||||
if((127.95f / 255 - sample_c().a) <0) // < 0x80 pass (== 0x80 should not pass)
|
||||
discard;
|
||||
|
||||
SV_Target0 = vec4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
void ps_main4()
|
||||
{
|
||||
// FIXME mod and fmod are different when value are negative
|
||||
// output.c = fmod(sample_c(input.t) * 255 + 0.5f, 256) / 255;
|
||||
vec4 c = mod(sample_c() * 255 + 0.5f, 256) / 255;
|
||||
|
||||
SV_Target0 = c;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,59 @@
|
|||
//#version 420 // Keep it for editor detection
|
||||
|
||||
struct vertex_basic
|
||||
{
|
||||
vec4 p;
|
||||
vec2 t;
|
||||
};
|
||||
|
||||
#ifdef FRAGMENT_SHADER
|
||||
layout(location = 0) in vertex_basic PSin;
|
||||
|
||||
layout(location = 0) out vec4 SV_Target0;
|
||||
|
||||
layout(std140, binding = 2) uniform cb0
|
||||
{
|
||||
vec2 ZrH;
|
||||
float hH;
|
||||
};
|
||||
|
||||
layout(binding = 0) uniform sampler2D TextureSampler;
|
||||
|
||||
// TODO ensure that clip (discard) is < 0 and not <= 0 ???
|
||||
void ps_main0()
|
||||
{
|
||||
// I'm not sure it impact us but be safe to lookup texture before conditional if
|
||||
// see: http://www.opengl.org/wiki/GLSL_Sampler#Non-uniform_flow_control
|
||||
vec4 c = texture(TextureSampler, PSin.t);
|
||||
if (fract(PSin.t.y * hH) - 0.5 < 0.0)
|
||||
discard;
|
||||
|
||||
SV_Target0 = c;
|
||||
}
|
||||
|
||||
void ps_main1()
|
||||
{
|
||||
// I'm not sure it impact us but be safe to lookup texture before conditional if
|
||||
// see: http://www.opengl.org/wiki/GLSL_Sampler#Non-uniform_flow_control
|
||||
vec4 c = texture(TextureSampler, PSin.t);
|
||||
if (0.5 - fract(PSin.t.y * hH) < 0.0)
|
||||
discard;
|
||||
|
||||
SV_Target0 = c;
|
||||
}
|
||||
|
||||
void ps_main2()
|
||||
{
|
||||
vec4 c0 = texture(TextureSampler, PSin.t - ZrH);
|
||||
vec4 c1 = texture(TextureSampler, PSin.t);
|
||||
vec4 c2 = texture(TextureSampler, PSin.t + ZrH);
|
||||
|
||||
SV_Target0 = (c0 + c1 * 2 + c2) / 4;
|
||||
}
|
||||
|
||||
void ps_main3()
|
||||
{
|
||||
SV_Target0 = texture(TextureSampler, PSin.t);
|
||||
}
|
||||
|
||||
#endif
|
Binary file not shown.
After Width: | Height: | Size: 73 KiB |
|
@ -0,0 +1,35 @@
|
|||
//#version 420 // Keep it for editor detection
|
||||
|
||||
struct vertex_basic
|
||||
{
|
||||
vec4 p;
|
||||
vec2 t;
|
||||
};
|
||||
|
||||
#ifdef FRAGMENT_SHADER
|
||||
layout(location = 0) in vertex_basic PSin;
|
||||
|
||||
layout(location = 0) out vec4 SV_Target0;
|
||||
|
||||
layout(std140, binding = 1) uniform cb0
|
||||
{
|
||||
vec4 BGColor;
|
||||
};
|
||||
|
||||
layout(binding = 0) uniform sampler2D TextureSampler;
|
||||
|
||||
void ps_main0()
|
||||
{
|
||||
vec4 c = texture(TextureSampler, PSin.t);
|
||||
c.a = min(c.a * 2, 1.0);
|
||||
SV_Target0 = c;
|
||||
}
|
||||
|
||||
void ps_main1()
|
||||
{
|
||||
vec4 c = texture(TextureSampler, PSin.t);
|
||||
c.a = BGColor.a;
|
||||
SV_Target0 = c;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,61 @@
|
|||
//#version 420 // Keep it for editor detection
|
||||
|
||||
/*
|
||||
** Contrast, saturation, brightness
|
||||
** Code of this function is from TGM's shader pack
|
||||
** http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=21057
|
||||
*/
|
||||
|
||||
struct vertex_basic
|
||||
{
|
||||
vec4 p;
|
||||
vec2 t;
|
||||
};
|
||||
|
||||
#ifdef FRAGMENT_SHADER
|
||||
|
||||
layout(location = 0) in vertex_basic PSin;
|
||||
|
||||
layout(location = 0) out vec4 SV_Target0;
|
||||
|
||||
layout(std140, binding = 6) uniform cb0
|
||||
{
|
||||
vec4 BGColor;
|
||||
};
|
||||
|
||||
layout(binding = 0) uniform sampler2D TextureSampler;
|
||||
|
||||
// For all settings: 1.0 = 100% 0.5=50% 1.5 = 150%
|
||||
vec4 ContrastSaturationBrightness(vec4 color)
|
||||
{
|
||||
const float sat = SB_SATURATION / 50.0;
|
||||
const float brt = SB_BRIGHTNESS / 50.0;
|
||||
const float con = SB_CONTRAST / 50.0;
|
||||
|
||||
// Increase or decrease theese values to adjust r, g and b color channels seperately
|
||||
const float AvgLumR = 0.5;
|
||||
const float AvgLumG = 0.5;
|
||||
const float AvgLumB = 0.5;
|
||||
|
||||
const vec3 LumCoeff = vec3(0.2125, 0.7154, 0.0721);
|
||||
|
||||
vec3 AvgLumin = vec3(AvgLumR, AvgLumG, AvgLumB);
|
||||
vec3 brtColor = color.rgb * brt;
|
||||
float dot_intensity = dot(brtColor, LumCoeff);
|
||||
vec3 intensity = vec3(dot_intensity, dot_intensity, dot_intensity);
|
||||
vec3 satColor = mix(intensity, brtColor, sat);
|
||||
vec3 conColor = mix(AvgLumin, satColor, con);
|
||||
|
||||
color.rgb = conColor;
|
||||
return color;
|
||||
}
|
||||
|
||||
|
||||
void ps_main()
|
||||
{
|
||||
vec4 c = texture(TextureSampler, PSin.t);
|
||||
SV_Target0 = ContrastSaturationBrightness(c);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,658 @@
|
|||
//#version 420 // Keep it for text editor detection
|
||||
|
||||
// note lerp => mix
|
||||
|
||||
#define FMT_32 0
|
||||
#define FMT_24 1
|
||||
#define FMT_16 2
|
||||
#define FMT_8H 3
|
||||
#define FMT_4HL 4
|
||||
#define FMT_4HH 5
|
||||
#define FMT_8 6
|
||||
|
||||
#ifndef VS_BPPZ
|
||||
#define VS_BPPZ 0
|
||||
#define VS_TME 1
|
||||
#define VS_FST 1
|
||||
#endif
|
||||
|
||||
#ifndef GS_IIP
|
||||
#define GS_IIP 0
|
||||
#define GS_PRIM 3
|
||||
#endif
|
||||
|
||||
#ifndef PS_FST
|
||||
#define PS_FST 0
|
||||
#define PS_WMS 0
|
||||
#define PS_WMT 0
|
||||
#define PS_FMT FMT_8
|
||||
#define PS_AEM 0
|
||||
#define PS_TFX 0
|
||||
#define PS_TCC 1
|
||||
#define PS_ATST 1
|
||||
#define PS_FOG 0
|
||||
#define PS_CLR1 0
|
||||
#define PS_FBA 0
|
||||
#define PS_AOUT 0
|
||||
#define PS_LTF 1
|
||||
#define PS_COLCLIP 0
|
||||
#define PS_DATE 0
|
||||
#define PS_SPRITEHACK 0
|
||||
#endif
|
||||
|
||||
struct vertex
|
||||
{
|
||||
vec4 p;
|
||||
vec4 t;
|
||||
vec4 tp;
|
||||
vec4 c;
|
||||
};
|
||||
|
||||
#ifdef VERTEX_SHADER
|
||||
layout(location = 0) in vec2 i_st;
|
||||
layout(location = 1) in vec4 i_c;
|
||||
layout(location = 2) in float i_q;
|
||||
layout(location = 3) in uvec2 i_p;
|
||||
layout(location = 4) in uint i_z;
|
||||
layout(location = 5) in uvec2 i_uv;
|
||||
layout(location = 6) in vec4 i_f;
|
||||
|
||||
layout(location = 0) out vertex VSout;
|
||||
|
||||
out gl_PerVertex {
|
||||
vec4 gl_Position;
|
||||
float gl_PointSize;
|
||||
float gl_ClipDistance[];
|
||||
};
|
||||
|
||||
layout(std140, binding = 4) uniform cb0
|
||||
{
|
||||
vec4 VertexScale;
|
||||
vec4 VertexOffset;
|
||||
vec2 TextureScale;
|
||||
};
|
||||
|
||||
void vs_main()
|
||||
{
|
||||
uint z;
|
||||
if(VS_BPPZ == 1) // 24
|
||||
z = i_z & uint(0xffffff);
|
||||
else if(VS_BPPZ == 2) // 16
|
||||
z = i_z & uint(0xffff);
|
||||
else
|
||||
z = i_z;
|
||||
|
||||
// pos -= 0.05 (1/320 pixel) helps avoiding rounding problems (integral part of pos is usually 5 digits, 0.05 is about as low as we can go)
|
||||
// example: ceil(afterseveralvertextransformations(y = 133)) => 134 => line 133 stays empty
|
||||
// input granularity is 1/16 pixel, anything smaller than that won't step drawing up/left by one pixel
|
||||
// example: 133.0625 (133 + 1/16) should start from line 134, ceil(133.0625 - 0.05) still above 133
|
||||
|
||||
vec4 p = vec4(i_p, z, 0) - vec4(0.05f, 0.05f, 0, 0);
|
||||
vec4 final_p = p * VertexScale - VertexOffset;
|
||||
// FIXME
|
||||
// FLIP vertically
|
||||
final_p.y *= -1.0f;
|
||||
|
||||
VSout.p = final_p;
|
||||
gl_Position = final_p; // NOTE I don't know if it is possible to merge POSITION_OUT and gl_Position
|
||||
#if VS_RTCOPY
|
||||
VSout.tp = final_p * vec4(0.5, -0.5, 0, 0) + 0.5;
|
||||
#endif
|
||||
|
||||
if(VS_TME != 0)
|
||||
{
|
||||
if(VS_FST != 0)
|
||||
{
|
||||
//VSout.t.xy = i_t * TextureScale;
|
||||
VSout.t.xy = i_uv * TextureScale;
|
||||
VSout.t.w = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
//VSout.t.xy = i_t;
|
||||
VSout.t.xy = i_st;
|
||||
VSout.t.w = i_q;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
VSout.t.xy = vec2(0.0f, 0.0f);
|
||||
VSout.t.w = 1.0f;
|
||||
}
|
||||
|
||||
VSout.c = i_c;
|
||||
VSout.t.z = i_f.r;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef GEOMETRY_SHADER
|
||||
in gl_PerVertex {
|
||||
vec4 gl_Position;
|
||||
float gl_PointSize;
|
||||
float gl_ClipDistance[];
|
||||
} gl_in[];
|
||||
|
||||
out gl_PerVertex {
|
||||
vec4 gl_Position;
|
||||
float gl_PointSize;
|
||||
float gl_ClipDistance[];
|
||||
};
|
||||
|
||||
// FIXME
|
||||
// AMD Driver bug again !!!!
|
||||
//layout(location = 0) in vertex GSin[];
|
||||
in vertex GSin[];
|
||||
|
||||
layout(location = 0) out vertex GSout;
|
||||
|
||||
#if GS_PRIM == 0
|
||||
layout(points) in;
|
||||
layout(points, max_vertices = 1) out;
|
||||
|
||||
void gs_main()
|
||||
{
|
||||
for(int i = 0; i < gl_in.length(); i++) {
|
||||
gl_Position = gl_in[i].gl_Position; // FIXME is it useful
|
||||
GSout = GSin[i];
|
||||
EmitVertex();
|
||||
}
|
||||
EndPrimitive();
|
||||
}
|
||||
|
||||
#elif GS_PRIM == 1
|
||||
layout(lines) in;
|
||||
layout(line_strip, max_vertices = 2) out;
|
||||
|
||||
void gs_main()
|
||||
{
|
||||
for(int i = 0; i < gl_in.length(); i++) {
|
||||
gl_Position = gl_in[i].gl_Position; // FIXME is it useful
|
||||
GSout = GSin[i];
|
||||
#if GS_IIP == 0
|
||||
if (i == 0)
|
||||
GSout.c = GSin[1].c;
|
||||
#endif
|
||||
EmitVertex();
|
||||
}
|
||||
EndPrimitive();
|
||||
}
|
||||
|
||||
#elif GS_PRIM == 2
|
||||
layout(triangles) in;
|
||||
layout(triangle_strip, max_vertices = 3) out;
|
||||
|
||||
void gs_main()
|
||||
{
|
||||
for(int i = 0; i < gl_in.length(); i++) {
|
||||
gl_Position = gl_in[i].gl_Position; // FIXME is it useful
|
||||
GSout = GSin[i];
|
||||
#if GS_IIP == 0
|
||||
if (i == 0 || i == 1)
|
||||
GSout.c = GSin[2].c;
|
||||
#endif
|
||||
EmitVertex();
|
||||
}
|
||||
EndPrimitive();
|
||||
}
|
||||
|
||||
#elif GS_PRIM == 3
|
||||
layout(lines) in;
|
||||
layout(triangle_strip, max_vertices = 6) out;
|
||||
|
||||
void gs_main()
|
||||
{
|
||||
// left top => GSin[0];
|
||||
// right bottom => GSin[1];
|
||||
vertex rb = GSin[1];
|
||||
vertex lt = GSin[0];
|
||||
|
||||
lt.p.z = rb.p.z;
|
||||
lt.t.zw = rb.t.zw;
|
||||
#if GS_IIP == 0
|
||||
lt.c = rb.c;
|
||||
#endif
|
||||
|
||||
vertex lb = rb;
|
||||
lb.p.x = lt.p.x;
|
||||
lb.t.x = lt.t.x;
|
||||
|
||||
vertex rt = rb;
|
||||
rt.p.y = lt.p.y;
|
||||
rt.t.y = lt.t.y;
|
||||
|
||||
// Triangle 1
|
||||
gl_Position = lt.p;
|
||||
GSout = lt;
|
||||
EmitVertex();
|
||||
|
||||
gl_Position = lb.p;
|
||||
GSout = lb;
|
||||
EmitVertex();
|
||||
|
||||
gl_Position = rt.p;
|
||||
GSout = rt;
|
||||
EmitVertex();
|
||||
|
||||
EndPrimitive();
|
||||
|
||||
// Triangle 2
|
||||
gl_Position = lb.p;
|
||||
GSout = lb;
|
||||
EmitVertex();
|
||||
|
||||
gl_Position = rt.p;
|
||||
GSout = rt;
|
||||
EmitVertex();
|
||||
|
||||
gl_Position = rb.p;
|
||||
GSout = rb;
|
||||
EmitVertex();
|
||||
|
||||
EndPrimitive();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef FRAGMENT_SHADER
|
||||
layout(location = 0) in vertex PSin;
|
||||
|
||||
// Same buffer but 2 colors for dual source blending
|
||||
#ifndef DISABLE_DUAL_BLEND
|
||||
layout(location = 0, index = 1) out vec4 SV_Target0;
|
||||
layout(location = 0, index = 0) out vec4 SV_Target1;
|
||||
#else
|
||||
layout(location = 0) out vec4 SV_Target1;
|
||||
#endif
|
||||
|
||||
layout(binding = 0) uniform sampler2D TextureSampler;
|
||||
layout(binding = 1) uniform sampler2D PaletteSampler;
|
||||
layout(binding = 2) uniform sampler2D RTCopySampler;
|
||||
|
||||
layout(std140, binding = 5) uniform cb1
|
||||
{
|
||||
vec3 FogColor;
|
||||
float AREF;
|
||||
vec4 HalfTexel;
|
||||
vec4 WH;
|
||||
vec4 MinMax;
|
||||
vec2 MinF;
|
||||
vec2 TA;
|
||||
uvec4 MskFix;
|
||||
};
|
||||
|
||||
vec4 sample_c(vec2 uv)
|
||||
{
|
||||
// FIXME I'm not sure it is a good solution to flip texture
|
||||
return texture(TextureSampler, uv);
|
||||
//FIXME another way to FLIP vertically
|
||||
//return texture(TextureSampler, vec2(uv.x, 1.0f-uv.y) );
|
||||
}
|
||||
|
||||
vec4 sample_p(float u)
|
||||
{
|
||||
//FIXME do we need a 1D sampler. Big impact on opengl to find 1 dim
|
||||
// So for the moment cheat with 0.0f dunno if it work
|
||||
return texture(PaletteSampler, vec2(u, 0.0f));
|
||||
}
|
||||
|
||||
vec4 sample_rt(vec2 uv)
|
||||
{
|
||||
return texture(RTCopySampler, uv);
|
||||
}
|
||||
|
||||
vec4 wrapuv(vec4 uv)
|
||||
{
|
||||
vec4 uv_out = uv;
|
||||
|
||||
if(PS_WMS == PS_WMT)
|
||||
{
|
||||
if(PS_WMS == 2)
|
||||
{
|
||||
uv_out = clamp(uv, MinMax.xyxy, MinMax.zwzw);
|
||||
}
|
||||
else if(PS_WMS == 3)
|
||||
{
|
||||
uv_out = vec4(((ivec4(uv * WH.xyxy) & ivec4(MskFix.xyxy)) | ivec4(MskFix.zwzw)) / WH.xyxy);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(PS_WMS == 2)
|
||||
{
|
||||
uv_out.xz = clamp(uv.xz, MinMax.xx, MinMax.zz);
|
||||
}
|
||||
else if(PS_WMS == 3)
|
||||
{
|
||||
uv_out.xz = vec2(((ivec2(uv.xz * WH.xx) & ivec2(MskFix.xx)) | ivec2(MskFix.zz)) / WH.xx);
|
||||
}
|
||||
if(PS_WMT == 2)
|
||||
{
|
||||
uv_out.yw = clamp(uv.yw, MinMax.yy, MinMax.ww);
|
||||
}
|
||||
else if(PS_WMT == 3)
|
||||
{
|
||||
uv_out.yw = vec2(((ivec2(uv.yw * WH.yy) & ivec2(MskFix.yy)) | ivec2(MskFix.ww)) / WH.yy);
|
||||
}
|
||||
}
|
||||
|
||||
return uv_out;
|
||||
}
|
||||
|
||||
vec2 clampuv(vec2 uv)
|
||||
{
|
||||
vec2 uv_out = uv;
|
||||
|
||||
if(PS_WMS == 2 && PS_WMT == 2)
|
||||
{
|
||||
uv_out = clamp(uv, MinF, MinMax.zw);
|
||||
}
|
||||
else if(PS_WMS == 2)
|
||||
{
|
||||
uv_out.x = clamp(uv.x, MinF.x, MinMax.z);
|
||||
}
|
||||
else if(PS_WMT == 2)
|
||||
{
|
||||
uv_out.y = clamp(uv.y, MinF.y, MinMax.w);
|
||||
}
|
||||
|
||||
return uv_out;
|
||||
}
|
||||
|
||||
mat4 sample_4c(vec4 uv)
|
||||
{
|
||||
mat4 c;
|
||||
|
||||
c[0] = sample_c(uv.xy);
|
||||
c[1] = sample_c(uv.zy);
|
||||
c[2] = sample_c(uv.xw);
|
||||
c[3] = sample_c(uv.zw);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
vec4 sample_4a(vec4 uv)
|
||||
{
|
||||
vec4 c;
|
||||
|
||||
c.x = sample_c(uv.xy).a;
|
||||
c.y = sample_c(uv.zy).a;
|
||||
c.z = sample_c(uv.xw).a;
|
||||
c.w = sample_c(uv.zw).a;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
mat4 sample_4p(vec4 u)
|
||||
{
|
||||
mat4 c;
|
||||
|
||||
c[0] = sample_p(u.x);
|
||||
c[1] = sample_p(u.y);
|
||||
c[2] = sample_p(u.z);
|
||||
c[3] = sample_p(u.w);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
vec4 sample_color(vec2 st, float q)
|
||||
{
|
||||
if(PS_FST == 0)
|
||||
{
|
||||
st /= q;
|
||||
}
|
||||
|
||||
vec4 t;
|
||||
if((PS_FMT <= FMT_16) && (PS_WMS < 3) && (PS_WMT < 3))
|
||||
{
|
||||
t = sample_c(clampuv(st));
|
||||
}
|
||||
else
|
||||
{
|
||||
vec4 uv;
|
||||
vec2 dd;
|
||||
|
||||
if(PS_LTF != 0)
|
||||
{
|
||||
uv = st.xyxy + HalfTexel;
|
||||
dd = fract(uv.xy * WH.zw);
|
||||
}
|
||||
else
|
||||
{
|
||||
uv = st.xyxy;
|
||||
}
|
||||
|
||||
uv = wrapuv(uv);
|
||||
|
||||
mat4 c;
|
||||
|
||||
if(PS_FMT == FMT_8H)
|
||||
{
|
||||
c = sample_4p(sample_4a(uv));
|
||||
}
|
||||
else if(PS_FMT == FMT_4HL)
|
||||
{
|
||||
// FIXME mod and fmod are different when value are negative
|
||||
c = sample_4p(mod(sample_4a(uv), 1.0f / 16));
|
||||
}
|
||||
else if(PS_FMT == FMT_4HH)
|
||||
{
|
||||
// FIXME mod and fmod are different when value are negative
|
||||
c = sample_4p(mod(sample_4a(uv) * 16, 1.0f / 16));
|
||||
}
|
||||
else if(PS_FMT == FMT_8)
|
||||
{
|
||||
c = sample_4p(sample_4a(uv));
|
||||
}
|
||||
else
|
||||
{
|
||||
c = sample_4c(uv);
|
||||
}
|
||||
|
||||
if(PS_LTF != 0)
|
||||
{
|
||||
t = mix(mix(c[0], c[1], dd.x), mix(c[2], c[3], dd.x), dd.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
t = c[0];
|
||||
}
|
||||
}
|
||||
|
||||
if(PS_FMT == FMT_32)
|
||||
{
|
||||
;
|
||||
}
|
||||
else if(PS_FMT == FMT_24)
|
||||
{
|
||||
// FIXME GLSL any only support bvec so try to mix it with notEqual
|
||||
bvec3 rgb_check = notEqual( t.rgb, vec3(0.0f, 0.0f, 0.0f) );
|
||||
t.a = ( (PS_AEM == 0) || any(rgb_check) ) ? TA.x : 0.0f;
|
||||
}
|
||||
else if(PS_FMT == FMT_16)
|
||||
{
|
||||
// a bit incompatible with up-scaling because the 1 bit alpha is interpolated
|
||||
// FIXME GLSL any only support bvec so try to mix it with notEqual
|
||||
bvec3 rgb_check = notEqual( t.rgb, vec3(0.0f, 0.0f, 0.0f) );
|
||||
t.a = t.a >= 0.5 ? TA.y : ( (PS_AEM == 0) || any(rgb_check) ) ? TA.x : 0.0f;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
vec4 tfx(vec4 t, vec4 c)
|
||||
{
|
||||
vec4 c_out = c;
|
||||
if(PS_TFX == 0)
|
||||
{
|
||||
if(PS_TCC != 0)
|
||||
{
|
||||
c_out = c * t * 255.0f / 128;
|
||||
}
|
||||
else
|
||||
{
|
||||
c_out.rgb = c.rgb * t.rgb * 255.0f / 128;
|
||||
}
|
||||
}
|
||||
else if(PS_TFX == 1)
|
||||
{
|
||||
if(PS_TCC != 0)
|
||||
{
|
||||
c_out = t;
|
||||
}
|
||||
else
|
||||
{
|
||||
c_out.rgb = t.rgb;
|
||||
}
|
||||
}
|
||||
else if(PS_TFX == 2)
|
||||
{
|
||||
c_out.rgb = c.rgb * t.rgb * 255.0f / 128 + c.a;
|
||||
|
||||
if(PS_TCC != 0)
|
||||
{
|
||||
c_out.a += t.a;
|
||||
}
|
||||
}
|
||||
else if(PS_TFX == 3)
|
||||
{
|
||||
c_out.rgb = c.rgb * t.rgb * 255.0f / 128 + c.a;
|
||||
|
||||
if(PS_TCC != 0)
|
||||
{
|
||||
c_out.a = t.a;
|
||||
}
|
||||
}
|
||||
|
||||
return clamp(c_out, vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
}
|
||||
|
||||
void datst()
|
||||
{
|
||||
#if PS_DATE > 0
|
||||
float alpha = sample_rt(PSin.tp.xy).a;
|
||||
float alpha0x80 = 128. / 255;
|
||||
|
||||
if (PS_DATE == 1 && alpha >= alpha0x80)
|
||||
discard;
|
||||
else if (PS_DATE == 2 && alpha < alpha0x80)
|
||||
discard;
|
||||
#endif
|
||||
}
|
||||
|
||||
void atst(vec4 c)
|
||||
{
|
||||
float a = trunc(c.a * 255);
|
||||
|
||||
if(PS_ATST == 0) // never
|
||||
{
|
||||
discard;
|
||||
}
|
||||
else if(PS_ATST == 1) // always
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
else if(PS_ATST == 2)
|
||||
{
|
||||
}
|
||||
else if(PS_ATST == 2 ) // l
|
||||
{
|
||||
if (PS_SPRITEHACK == 0)
|
||||
if ((AREF - a) < 0.0f)
|
||||
discard;
|
||||
}
|
||||
else if(PS_ATST == 2 ) // le
|
||||
{
|
||||
if ((AREF - a) < 0.0f)
|
||||
discard;
|
||||
}
|
||||
else if(PS_ATST == 4) // e
|
||||
{
|
||||
if ((0.5f - abs(a - AREF)) < 0.0f)
|
||||
discard;
|
||||
}
|
||||
else if(PS_ATST == 5 || PS_ATST == 6) // ge, g
|
||||
{
|
||||
if ((a-AREF) < 0.0f)
|
||||
discard;
|
||||
}
|
||||
else if(PS_ATST == 7) // ne
|
||||
{
|
||||
if ((abs(a - AREF) - 0.5f) < 0.0f)
|
||||
discard;
|
||||
}
|
||||
}
|
||||
|
||||
vec4 fog(vec4 c, float f)
|
||||
{
|
||||
vec4 c_out = c;
|
||||
if(PS_FOG != 0)
|
||||
{
|
||||
c_out.rgb = mix(FogColor, c.rgb, f);
|
||||
}
|
||||
|
||||
return c_out;
|
||||
}
|
||||
|
||||
vec4 ps_color()
|
||||
{
|
||||
datst();
|
||||
|
||||
vec4 t = sample_color(PSin.t.xy, PSin.t.w);
|
||||
|
||||
vec4 c = tfx(t, PSin.c);
|
||||
|
||||
atst(c);
|
||||
|
||||
c = fog(c, PSin.t.z);
|
||||
|
||||
if (PS_COLCLIP == 2)
|
||||
{
|
||||
c.rgb = 256.0f/255.0f - c.rgb;
|
||||
}
|
||||
if (PS_COLCLIP > 0)
|
||||
{
|
||||
// FIXME !!!!
|
||||
//c.rgb *= c.rgb < 128./255;
|
||||
bvec3 factor = bvec3(128.0f/255.0f, 128.0f/255.0f, 128.0f/255.0f);
|
||||
c.rgb *= vec3(factor);
|
||||
}
|
||||
|
||||
if(PS_CLR1 != 0) // needed for Cd * (As/Ad/F + 1) blending modes
|
||||
{
|
||||
c.rgb = vec3(1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void ps_main()
|
||||
{
|
||||
//FIXME
|
||||
vec4 c = ps_color();
|
||||
|
||||
// FIXME: I'm not sure about the value of others field
|
||||
// output.c1 = c.a * 2; // used for alpha blending
|
||||
|
||||
float alpha = c.a * 2;
|
||||
|
||||
if(PS_AOUT != 0) // 16 bit output
|
||||
{
|
||||
float a = 128.0f / 255; // alpha output will be 0x80
|
||||
|
||||
c.a = (PS_FBA != 0) ? a : step(0.5, c.a) * a;
|
||||
}
|
||||
else if(PS_FBA != 0)
|
||||
{
|
||||
if(c.a < 0.5) c.a += 0.5;
|
||||
}
|
||||
|
||||
SV_Target1 = c;
|
||||
#ifndef DISABLE_DUAL_BLEND
|
||||
SV_Target0 = vec4(alpha, alpha, alpha, alpha);
|
||||
#endif
|
||||
}
|
||||
#endif
|
|
@ -198,6 +198,11 @@ using namespace std;
|
|||
//#include <ext/hash_map>
|
||||
//#include <ext/hash_set>
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glx.h>
|
||||
#include <GL/glext.h>
|
||||
|
||||
//using namespace __gnu_cxx;
|
||||
|
||||
#define DIRECTORY_SEPARATOR '/'
|
||||
|
|
Loading…
Reference in New Issue