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:
gregory.hainaut 2012-04-28 15:24:02 +00:00
commit 46838ca4ee
36 changed files with 8755 additions and 278 deletions

View File

@ -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
};

View File

@ -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

View File

@ -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)
#---------------------------------------
#---------------------------------------

View File

@ -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)

View File

@ -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;
}

View File

@ -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

1524
plugins/GSdx/GSDeviceOGL.cpp Normal file

File diff suppressed because it is too large Load Diff

922
plugins/GSdx/GSDeviceOGL.h Normal file
View File

@ -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);
};

View File

@ -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

View File

@ -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

View File

@ -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);

2649
plugins/GSdx/GSLinuxLogo.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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);
};

View File

@ -21,6 +21,8 @@
#pragma once
#include "stdafx.h"
struct GSSetting
{
uint32 id;

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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);
};

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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; }
};

View File

@ -52,7 +52,7 @@ struct GSVertexP
GSVector4 p;
};
struct GSVertexPT1
__aligned(struct, 32) GSVertexPT1
{
GSVector4 p;
GSVector2 t;

View File

@ -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];
}

View File

@ -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()

View File

@ -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

View File

@ -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"));

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

658
plugins/GSdx/res/tfx.glsl Normal file
View File

@ -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

View File

@ -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 '/'