fork GSdx into a GSdx_legacy plugin

This commit is contained in:
Gregory Hainaut 2016-04-07 21:27:55 +02:00
parent 8ccdc05c08
commit 8751203986
290 changed files with 129074 additions and 0 deletions

View File

@ -0,0 +1,228 @@
# Check that people use the good file
if(NOT TOP_CMAKE_WAS_SOURCED)
message(FATAL_ERROR "
You did not 'cmake' the good CMakeLists.txt file. Use the one in the top dir.
It is advice to delete all wrongly generated cmake stuff => CMakeFiles & CMakeCache.txt")
endif()
# plugin name
set(Output GSdx-1.0.0)
set(CommonFlags
-fno-operator-names # because Xbyak uses and()/xor()/or()/not() function
-fno-strict-aliasing
-Wno-unknown-pragmas
-Wno-parentheses
-Wunused-variable # __dummy variable need to be investigated
)
set(GSdxFinalFlags ${CommonFlags})
if(XDG_STD)
set(GSdxFinalFlags ${GSdxFinalFlags} -DXDG_STD)
endif()
if(EGL_API AND EGL_FOUND)
set(GSdxFinalFlags ${GSdxFinalFlags} -DEGL_SUPPORTED)
endif()
if(LIBLZMA_FOUND)
set(GSdxFinalFlags ${GSdxFinalFlags} -DLZMA_SUPPORTED)
endif()
#Clang doesn't support a few common flags that GCC does.
if(NOT USE_CLANG)
set(GSdxFinalFlags ${GSdxFinalFlags} -fabi-version=6)
endif()
set(GSdxSources
GLLoader.cpp
GLState.cpp
GPU.cpp
GPUDrawScanline.cpp
GPUDrawScanlineCodeGenerator.cpp
GPULocalMemory.cpp
GPURenderer.cpp
GPURendererSW.cpp
GPUSetupPrimCodeGenerator.cpp
GPUState.cpp
GS.cpp
GSAlignedClass.cpp
GSBlock.cpp
GSCapture.cpp
GSClut.cpp
GSCodeBuffer.cpp
GSCrc.cpp
GSDevice.cpp
GSDeviceOGL.cpp
GSDeviceSW.cpp
GSDeviceNull.cpp
GSDirtyRect.cpp
GSDrawingContext.cpp
GSDrawScanline.cpp
GSDrawScanlineCodeGenerator.cpp
GSDrawScanlineCodeGenerator.x86.avx.cpp
GSDrawScanlineCodeGenerator.x86.avx2.cpp
GSDrawScanlineCodeGenerator.x64.cpp
GSDrawScanlineCodeGenerator.x86.cpp
GSDrawScanlineCodeGenerator.x64.avx.cpp
GSDump.cpp
GSFunctionMap.cpp
GSLinuxDialog.cpp
GSLocalMemory.cpp
GSLzma.cpp
GSPerfMon.cpp
GSPng.cpp
GSRasterizer.cpp
GSRenderer.cpp
GSRendererCL.cpp
GSRendererHW.cpp
GSRendererNull.cpp
GSRendererOGL.cpp
GSRendererSW.cpp
GSSetting.cpp
GSSetupPrimCodeGenerator.cpp
GSSetupPrimCodeGenerator.x86.avx.cpp
GSSetupPrimCodeGenerator.x86.avx2.cpp
GSSetupPrimCodeGenerator.x64.avx.cpp
GSSetupPrimCodeGenerator.x86.cpp
GSSetupPrimCodeGenerator.x64.cpp
GSShaderOGL.cpp
GSState.cpp
GSTables.cpp
GSTexture.cpp
GSTextureCache.cpp
GSTextureCacheSW.cpp
GSTextureCacheOGL.cpp
GSTextureFXOGL.cpp
GSTextureOGL.cpp
GSTextureNull.cpp
GSTextureSW.cpp
GSThread.cpp
GSUtil.cpp
GSVector.cpp
GSVertexTrace.cpp
GSWnd.cpp
GSWndOGL.cpp
GSWndEGL.cpp
GSdx.cpp
stdafx.cpp
)
set(GSdxHeaders
GPU.h
GPUDrawScanline.h
GPUDrawScanlineCodeGenerator.h
GPUDrawingEnvironment.h
GPULocalMemory.h
GPURenderer.h
GPURendererSW.h
GPUScanlineEnvironment.h
GPUSetupPrimCodeGenerator.h
GPUState.h
GPUVertex.h
GS.h
GSAlignedClass.h
GSBlock.h
GSCapture.h
GSClut.h
GSCodeBuffer.h
GSCrc.h
GSDevice.h
GSDeviceOGL.h
GSDeviceNull.h
GSDirtyRect.h
GSDrawScanline.h
GSDrawScanlineCodeGenerator.h
GSDrawingContext.h
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
GSState.h
GSTables.h
GSTexture.h
GSTextureCache.h
GSTextureCacheSW.h
GSTextureCacheOGL.h
GSTextureNull.h
GSThread.h
GSUtil.h
GSVector.h
GSVertex.h
GSVertexHW.h
GSVertexList.h
GSVertexSW.h
GSVertexTrace.h
GSWnd.h
GSWndOGL.h
GSWndEGL.h
GSdx.h
res/glsl_source.h
stdafx.h
xbyak/xbyak.h
xbyak/xbyak_bin2hex.h
xbyak/xbyak_mnemonic.h
xbyak/xbyak_util.h
)
set(GSdxFinalSources
${GSdxSources}
${GSdxHeaders}
)
set(GSdxFinalLibs
${X11_LIBRARIES}
)
set(GSdxFinalLibs ${GSdxFinalLibs}
${OPENGL_LIBRARIES}
${GTK2_LIBRARIES}
${LIBC_LIBRARIES}
${PNG_LIBRARY}
)
if(EGL_API AND EGL_FOUND)
set(GSdxFinalLibs ${GSdxFinalLibs}
${EGL_LIBRARIES}
)
endif()
if(LIBLZMA_FOUND)
set(GSdxFinalLibs ${GSdxFinalLibs}
${LIBLZMA_LIBRARIES}
)
endif()
# Generate Glsl header file. Protect with REBUILD_SHADER to avoid build-dependency on PERL
if (REBUILD_SHADER)
add_custom_command(OUTPUT res/glsl_source.h COMMAND perl ${CMAKE_SOURCE_DIR}/linux_various/glsl2h.pl)
endif()
if(BUILTIN_GS)
add_pcsx2_lib(${Output} "${GSdxFinalSources}" "${GSdxFinalLibs}" "${GSdxFinalFlags}")
else()
add_pcsx2_plugin(${Output} "${GSdxFinalSources}" "${GSdxFinalLibs}" "${GSdxFinalFlags}")
endif()
################################### Replay Loader
if(BUILD_REPLAY_LOADERS)
set(Replay pcsx2_GSReplayLoader)
set(GSdxReplayLoaderFinalSources
${GSdxFinalSources}
linux_replay.cpp
)
add_pcsx2_executable(${Replay} "${GSdxReplayLoaderFinalSources}" "${GSdxFinalLibs}" "${GSdxFinalFlags}")
endif(BUILD_REPLAY_LOADERS)

View File

@ -0,0 +1,532 @@
/* * Copyright (C) 2011-2014 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GLLoader.h"
#include "GSdx.h"
PFNGLACTIVETEXTUREPROC gl_ActiveTexture = NULL;
PFNGLBLENDCOLORPROC gl_BlendColor = NULL;
PFNGLATTACHSHADERPROC glAttachShader = NULL;
PFNGLBINDBUFFERPROC glBindBuffer = NULL;
PFNGLBINDBUFFERBASEPROC glBindBufferBase = NULL;
PFNGLBINDBUFFERRANGEPROC glBindBufferRange = NULL;
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer = NULL;
PFNGLBINDSAMPLERPROC glBindSampler = NULL;
PFNGLBINDVERTEXARRAYPROC glBindVertexArray = NULL;
PFNGLBLENDEQUATIONSEPARATEIARBPROC glBlendEquationSeparateiARB = NULL;
PFNGLBLENDFUNCSEPARATEIARBPROC glBlendFuncSeparateiARB = NULL;
PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer = NULL;
PFNGLBUFFERDATAPROC glBufferData = NULL;
PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus = NULL;
PFNGLCLEARBUFFERFVPROC glClearBufferfv = NULL;
PFNGLCLEARBUFFERIVPROC glClearBufferiv = NULL;
PFNGLCLEARBUFFERUIVPROC glClearBufferuiv = NULL;
PFNGLCOLORMASKIPROC glColorMaski = NULL;
PFNGLCOMPILESHADERPROC glCompileShader = NULL;
PFNGLCREATEPROGRAMPROC glCreateProgram = NULL;
PFNGLCREATESHADERPROC glCreateShader = NULL;
PFNGLCREATESHADERPROGRAMVPROC glCreateShaderProgramv = NULL;
PFNGLDELETEBUFFERSPROC glDeleteBuffers = NULL;
PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers = NULL;
PFNGLDELETEPROGRAMPROC glDeleteProgram = NULL;
PFNGLDELETESAMPLERSPROC glDeleteSamplers = NULL;
PFNGLDELETESHADERPROC glDeleteShader = NULL;
PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays = NULL;
PFNGLDETACHSHADERPROC glDetachShader = NULL;
PFNGLDRAWBUFFERSPROC glDrawBuffers = NULL;
PFNGLDRAWELEMENTSBASEVERTEXPROC glDrawElementsBaseVertex = NULL;
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray = NULL;
PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer = NULL;
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = NULL;
PFNGLGENBUFFERSPROC glGenBuffers = NULL;
PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers = NULL;
PFNGLGENSAMPLERSPROC glGenSamplers = NULL;
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays = NULL;
PFNGLGETBUFFERPARAMETERIVPROC glGetBufferParameteriv = NULL;
PFNGLGETDEBUGMESSAGELOGARBPROC glGetDebugMessageLogARB = NULL;
PFNGLDEBUGMESSAGECALLBACKPROC glDebugMessageCallback = NULL;
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog = NULL;
PFNGLGETPROGRAMIVPROC glGetProgramiv = NULL;
PFNGLGETSHADERIVPROC glGetShaderiv = NULL;
PFNGLGETSTRINGIPROC glGetStringi = NULL;
PFNGLISFRAMEBUFFERPROC glIsFramebuffer = NULL;
PFNGLLINKPROGRAMPROC glLinkProgram = NULL;
PFNGLMAPBUFFERPROC glMapBuffer = NULL;
PFNGLMAPBUFFERRANGEPROC glMapBufferRange = NULL;
PFNGLPROGRAMPARAMETERIPROC glProgramParameteri = NULL;
PFNGLSAMPLERPARAMETERFPROC glSamplerParameterf = NULL;
PFNGLSAMPLERPARAMETERIPROC glSamplerParameteri = NULL;
PFNGLSHADERSOURCEPROC glShaderSource = NULL;
PFNGLUNIFORM1IPROC glUniform1i = NULL;
PFNGLUNMAPBUFFERPROC glUnmapBuffer = NULL;
PFNGLUSEPROGRAMSTAGESPROC glUseProgramStages = NULL;
PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer = NULL;
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer = NULL;
PFNGLBUFFERSUBDATAPROC glBufferSubData = NULL;
PFNGLFENCESYNCPROC glFenceSync = NULL;
PFNGLDELETESYNCPROC glDeleteSync = NULL;
PFNGLCLIENTWAITSYNCPROC glClientWaitSync = NULL;
PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange = NULL;
PFNGLBLENDEQUATIONSEPARATEPROC glBlendEquationSeparate = NULL;
PFNGLBLENDFUNCSEPARATEPROC glBlendFuncSeparate = NULL;
// Query object
PFNGLBEGINQUERYPROC glBeginQuery = NULL;
PFNGLENDQUERYPROC glEndQuery = NULL;
PFNGLGETQUERYIVPROC glGetQueryiv = NULL;
PFNGLGETQUERYOBJECTIVPROC glGetQueryObjectiv = NULL;
PFNGLGETQUERYOBJECTUIVPROC glGetQueryObjectuiv = NULL;
PFNGLQUERYCOUNTERPROC glQueryCounter = NULL;
PFNGLGETQUERYOBJECTI64VPROC glGetQueryObjecti64v = NULL;
PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v = NULL;
PFNGLGETINTEGER64VPROC glGetInteger64v = NULL;
// GL4.0
// GL4.1
PFNGLBINDPROGRAMPIPELINEPROC glBindProgramPipeline = NULL;
PFNGLGENPROGRAMPIPELINESPROC glGenProgramPipelines = NULL;
PFNGLDELETEPROGRAMPIPELINESPROC glDeleteProgramPipelines = NULL;
PFNGLGETPROGRAMPIPELINEIVPROC glGetProgramPipelineiv = NULL;
PFNGLVALIDATEPROGRAMPIPELINEPROC glValidateProgramPipeline = NULL;
PFNGLGETPROGRAMPIPELINEINFOLOGPROC glGetProgramPipelineInfoLog = NULL;
PFNGLGETPROGRAMBINARYPROC glGetProgramBinary = NULL;
PFNGLVIEWPORTINDEXEDFPROC glViewportIndexedf = NULL;
PFNGLVIEWPORTINDEXEDFVPROC glViewportIndexedfv = NULL;
PFNGLSCISSORINDEXEDPROC glScissorIndexed = NULL;
PFNGLSCISSORINDEXEDVPROC glScissorIndexedv = NULL;
// NO GL4.1
PFNGLUSEPROGRAMPROC glUseProgram = NULL;
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog = NULL;
PFNGLPROGRAMUNIFORM1IPROC glProgramUniform1i = NULL;
// GL4.3
PFNGLCOPYIMAGESUBDATAPROC glCopyImageSubData = NULL;
PFNGLINVALIDATETEXIMAGEPROC glInvalidateTexImage = NULL;
PFNGLPUSHDEBUGGROUPPROC glPushDebugGroup = NULL;
PFNGLPOPDEBUGGROUPPROC glPopDebugGroup = NULL;
PFNGLDEBUGMESSAGEINSERTPROC glDebugMessageInsert = NULL;
PFNGLDEBUGMESSAGECONTROLPROC glDebugMessageControl = NULL;
// GL4.2
PFNGLBINDIMAGETEXTUREPROC glBindImageTexture = NULL;
PFNGLMEMORYBARRIERPROC glMemoryBarrier = NULL;
PFNGLTEXSTORAGE2DPROC glTexStorage2D = NULL;
// GL4.4
PFNGLCLEARTEXIMAGEPROC glClearTexImage = NULL;
PFNGLBUFFERSTORAGEPROC glBufferStorage = NULL;
// GL4.5
PFNGLCREATETEXTURESPROC glCreateTextures = NULL;
PFNGLTEXTURESTORAGE2DPROC glTextureStorage2D = NULL;
PFNGLTEXTURESUBIMAGE2DPROC glTextureSubImage2D = NULL;
PFNGLCOPYTEXTURESUBIMAGE2DPROC glCopyTextureSubImage2D = NULL;
PFNGLBINDTEXTUREUNITPROC glBindTextureUnit = NULL;
PFNGLGETTEXTUREIMAGEPROC glGetTextureImage = NULL;
PFNGLTEXTUREPARAMETERIPROC glTextureParameteri = NULL;
PFNGLCREATEFRAMEBUFFERSPROC glCreateFramebuffers = NULL;
PFNGLCLEARNAMEDFRAMEBUFFERFVPROC glClearNamedFramebufferfv = NULL;
PFNGLCLEARNAMEDFRAMEBUFFERIVPROC glClearNamedFramebufferiv = NULL;
PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC glClearNamedFramebufferuiv = NULL;
PFNGLNAMEDFRAMEBUFFERTEXTUREPROC glNamedFramebufferTexture = NULL;
PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC glNamedFramebufferDrawBuffers = NULL;
PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC glNamedFramebufferReadBuffer = NULL;
PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC glCheckNamedFramebufferStatus = NULL;
PFNGLCREATEBUFFERSPROC glCreateBuffers = NULL;
PFNGLNAMEDBUFFERSTORAGEPROC glNamedBufferStorage = NULL;
PFNGLNAMEDBUFFERDATAPROC glNamedBufferData = NULL;
PFNGLNAMEDBUFFERSUBDATAPROC glNamedBufferSubData = NULL;
PFNGLMAPNAMEDBUFFERPROC glMapNamedBuffer = NULL;
PFNGLMAPNAMEDBUFFERRANGEPROC glMapNamedBufferRange = NULL;
PFNGLUNMAPNAMEDBUFFERPROC glUnmapNamedBuffer = NULL;
PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC glFlushMappedNamedBufferRange = NULL;
PFNGLCREATESAMPLERSPROC glCreateSamplers = NULL;
PFNGLCREATEPROGRAMPIPELINESPROC glCreateProgramPipelines = NULL;
PFNGLCLIPCONTROLPROC glClipControl = NULL;
PFNGLTEXTUREBARRIERPROC glTextureBarrier = NULL;
namespace Emulate_DSA {
// Texture entry point
void APIENTRY BindTextureUnit(GLuint unit, GLuint texture) {
gl_ActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(GL_TEXTURE_2D, texture);
}
void APIENTRY CreateTexture(GLenum target, GLsizei n, GLuint *textures) {
glGenTextures(1, textures);
}
void APIENTRY TextureStorage(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) {
BindTextureUnit(7, texture);
glTexStorage2D(GL_TEXTURE_2D, levels, internalformat, width, height);
}
void APIENTRY TextureSubImage(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) {
BindTextureUnit(7, texture);
glTexSubImage2D(GL_TEXTURE_2D, level, xoffset, yoffset, width, height, format, type, pixels);
}
void APIENTRY CopyTextureSubImage(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {
BindTextureUnit(7, texture);
glCopyTexSubImage2D(GL_TEXTURE_2D, level, xoffset, yoffset, x, y, width, height);
}
void APIENTRY GetTexureImage(GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels) {
BindTextureUnit(7, texture);
glGetTexImage(GL_TEXTURE_2D, level, format, type, pixels);
}
void APIENTRY TextureParameteri (GLuint texture, GLenum pname, GLint param) {
BindTextureUnit(7, texture);
glTexParameteri(GL_TEXTURE_2D, pname, param);
}
// Framebuffer entry point
GLenum fb_target = 0;
void SetFramebufferTarget(GLenum target) {
fb_target = target;
}
void APIENTRY CreateFramebuffers(GLsizei n, GLuint *framebuffers) {
glGenFramebuffers(n, framebuffers);
}
void APIENTRY ClearNamedFramebufferfv(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat *value) {
glBindFramebuffer(fb_target, framebuffer);
glClearBufferfv(buffer, drawbuffer, value);
}
void APIENTRY ClearNamedFramebufferiv(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint *value) {
glBindFramebuffer(fb_target, framebuffer);
glClearBufferiv(buffer, drawbuffer, value);
}
void APIENTRY ClearNamedFramebufferuiv(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint *value) {
glBindFramebuffer(fb_target, framebuffer);
glClearBufferuiv(buffer, drawbuffer, value);
}
void APIENTRY NamedFramebufferTexture(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level) {
glBindFramebuffer(fb_target, framebuffer);
glFramebufferTexture2D(fb_target, attachment, GL_TEXTURE_2D, texture, level);
}
void APIENTRY NamedFramebufferDrawBuffers(GLuint framebuffer, GLsizei n, const GLenum *bufs) {
glBindFramebuffer(fb_target, framebuffer);
glDrawBuffers(n, bufs);
}
void APIENTRY NamedFramebufferReadBuffer(GLuint framebuffer, GLenum src) {
glBindFramebuffer(fb_target, framebuffer);
glReadBuffer(src);
glBindFramebuffer(fb_target, 0);
}
GLenum APIENTRY CheckNamedFramebufferStatus(GLuint framebuffer, GLenum target) {
glBindFramebuffer(fb_target, framebuffer);
return glCheckFramebufferStatus(fb_target);
}
// Buffer entry point
GLenum buffer_target = 0;
void SetBufferTarget(GLenum target) {
buffer_target = target;
}
void APIENTRY CreateBuffers(GLsizei n, GLuint *buffers) {
glGenBuffers(1, buffers);
}
void APIENTRY NamedBufferStorage(GLuint buffer, buffer_proc_t size, const void *data, GLbitfield flags) {
glBindBuffer(buffer_target, buffer);
glBufferStorage(buffer_target, size, data, flags);
}
void APIENTRY NamedBufferData(GLuint buffer, buffer_proc_t size, const void *data, GLenum usage) {
glBindBuffer(buffer_target, buffer);
glBufferData(buffer_target, size, data, usage);
}
void APIENTRY NamedBufferSubData(GLuint buffer, GLintptr offset, buffer_proc_t size, const void *data) {
glBindBuffer(buffer_target, buffer);
glBufferSubData(buffer_target, offset, size, data);
}
void *APIENTRY MapNamedBuffer(GLuint buffer, GLenum access) {
glBindBuffer(buffer_target, buffer);
return glMapBuffer(buffer_target, access);
}
void *APIENTRY MapNamedBufferRange(GLuint buffer, GLintptr offset, buffer_proc_t length, GLbitfield access) {
glBindBuffer(buffer_target, buffer);
return glMapBufferRange(buffer_target, offset, length, access);
}
GLboolean APIENTRY UnmapNamedBuffer(GLuint buffer) {
glBindBuffer(buffer_target, buffer);
return glUnmapBuffer(buffer_target);
}
void APIENTRY FlushMappedNamedBufferRange(GLuint buffer, GLintptr offset, buffer_proc_t length) {
glBindBuffer(buffer_target, buffer);
glFlushMappedBufferRange(buffer_target, offset, length);
}
// Misc entry point
// (only purpose is to have a consistent API otherwise it is useless)
void APIENTRY CreateProgramPipelines(GLsizei n, GLuint *pipelines) {
glGenProgramPipelines(n, pipelines);
}
void APIENTRY CreateSamplers(GLsizei n, GLuint *samplers) {
glGenSamplers(n, samplers);
}
// Replace function pointer to emulate DSA behavior
void Init() {
fprintf(stderr, "DSA is not supported. Replacing the GL function pointer to emulate it\n");
glBindTextureUnit = BindTextureUnit;
glCreateTextures = CreateTexture;
glTextureStorage2D = TextureStorage;
glTextureSubImage2D = TextureSubImage;
glCopyTextureSubImage2D = CopyTextureSubImage;
glGetTextureImage = GetTexureImage;
glTextureParameteri = TextureParameteri;
glCreateFramebuffers = CreateFramebuffers;
glClearNamedFramebufferfv = ClearNamedFramebufferfv;
glClearNamedFramebufferiv = ClearNamedFramebufferiv;
glClearNamedFramebufferuiv = ClearNamedFramebufferuiv;
glNamedFramebufferDrawBuffers = NamedFramebufferDrawBuffers;
glNamedFramebufferReadBuffer = NamedFramebufferReadBuffer;
glCheckNamedFramebufferStatus = CheckNamedFramebufferStatus;
glCreateBuffers = CreateBuffers;
glNamedBufferStorage = NamedBufferStorage;
glNamedBufferData = NamedBufferData;
glNamedBufferSubData = NamedBufferSubData;
glMapNamedBuffer = MapNamedBuffer;
glMapNamedBufferRange = MapNamedBufferRange;
glUnmapNamedBuffer = UnmapNamedBuffer;
glFlushMappedNamedBufferRange = FlushMappedNamedBufferRange;
glCreateProgramPipelines = CreateProgramPipelines;
glCreateSamplers = CreateSamplers;
}
}
namespace GLLoader {
bool fglrx_buggy_driver = false;
bool mesa_amd_buggy_driver = false;
bool nvidia_buggy_driver = false;
bool intel_buggy_driver = false;
bool in_replayer = false;
bool found_geometry_shader = true; // we require GL3.3 so geometry must be supported by default
bool found_GL_EXT_texture_filter_anisotropic = false;
bool found_GL_ARB_clear_texture = false; // Miss AMD Mesa (otherwise seems SW)
// DX10 GPU limited driver (SW)
bool found_GL_ARB_copy_image = false;
bool found_GL_ARB_texture_barrier = false;
bool found_GL_ARB_clip_control = false;
bool found_GL_ARB_direct_state_access = false;
bool found_GL_ARB_separate_shader_objects = false; // Issue with Catalyst...
bool found_GL_ARB_buffer_storage = false;
// DX11 GPU
bool found_GL_ARB_draw_buffers_blend = false; // Not supported on AMD R600 (80 nm class chip, HD2900). Nvidia requires FERMI. Intel SB
bool found_GL_ARB_gpu_shader5 = false; // Require IvyBridge
bool found_GL_ARB_shader_image_load_store = false; // Intel IB. Nvidia/AMD miss Mesa implementation.
bool found_GL_ARB_viewport_array = false; // Intel IB. AMD/NVIDIA DX10
// Mandatory
bool found_GL_ARB_texture_storage = false;
bool found_GL_ARB_shading_language_420pack = false;
static bool status_and_override(bool& found, const std::string& name, bool mandatory = false)
{
if (mandatory) {
if (!found) {
fprintf(stderr, "ERROR: %s is NOT SUPPORTED\n", name.c_str());
}
return found;
}
if (!found) {
fprintf(stdout, "INFO: %s is NOT SUPPORTED\n", name.c_str());
} else {
fprintf(stdout, "INFO: %s is available\n", name.c_str());
}
std::string opt("override_");
opt += name;
if (theApp.GetConfig(opt.c_str(), -1) != -1) {
found = !!theApp.GetConfig(opt.c_str(), -1);
fprintf(stderr, "Override %s detection (%s)\n", name.c_str(), found ? "Enabled" : "Disabled");
}
return true;
}
bool check_gl_version(int major, int minor) {
const GLubyte* s = glGetString(GL_VERSION);
if (s == NULL) {
fprintf(stderr, "Error: GLLoader failed to get GL version\n");
return false;
}
GLuint v = 1;
while (s[v] != '\0' && s[v-1] != ' ') v++;
const char* vendor = (const char*)glGetString(GL_VENDOR);
fprintf(stdout, "OpenGL information. GPU: %s. Vendor: %s. Driver: %s\n", glGetString(GL_RENDERER), vendor, &s[v]);
// Name changed but driver is still bad!
if (strstr(vendor, "ATI") || strstr(vendor, "Advanced Micro Devices"))
fglrx_buggy_driver = true;
if (strstr(vendor, "NVIDIA Corporation"))
nvidia_buggy_driver = true;
if (strstr(vendor, "Intel"))
intel_buggy_driver = true;
if (strstr(vendor, "X.Org") || strstr(vendor, "nouveau")) // Note: it might actually catch nouveau too, but bugs are likely to be the same anyway
mesa_amd_buggy_driver = true;
if (strstr(vendor, "VMware")) // Assume worst case because I don't know the real status
mesa_amd_buggy_driver = intel_buggy_driver = true;
if (mesa_amd_buggy_driver) {
fprintf(stderr, "Buggy driver detected. Geometry shaders will be disabled\n");
found_geometry_shader = false;
}
if (theApp.GetConfig("override_geometry_shader", -1) != -1) {
found_geometry_shader = !!theApp.GetConfig("override_geometry_shader", -1);
fprintf(stderr, "Overriding geometry shaders detection\n");
}
GLint major_gl = 0;
GLint minor_gl = 0;
glGetIntegerv(GL_MAJOR_VERSION, &major_gl);
glGetIntegerv(GL_MINOR_VERSION, &minor_gl);
if ( (major_gl < major) || ( major_gl == major && minor_gl < minor ) ) {
fprintf(stderr, "OpenGL %d.%d is not supported. Only OpenGL %d.%d\n was found", major, minor, major_gl, minor_gl);
return false;
}
return true;
}
bool check_gl_supported_extension() {
int max_ext = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &max_ext);
if (glGetStringi && max_ext) {
for (GLint i = 0; i < max_ext; i++) {
string ext((const char*)glGetStringi(GL_EXTENSIONS, i));
// Bonus
if (ext.compare("GL_EXT_texture_filter_anisotropic") == 0) found_GL_EXT_texture_filter_anisotropic = true;
// GL4.0
if (ext.compare("GL_ARB_gpu_shader5") == 0) found_GL_ARB_gpu_shader5 = true;
if (ext.compare("GL_ARB_draw_buffers_blend") == 0) found_GL_ARB_draw_buffers_blend = true;
// GL4.1
if (ext.compare("GL_ARB_viewport_array") == 0) found_GL_ARB_viewport_array = true;
if (ext.compare("GL_ARB_separate_shader_objects") == 0) {
if (!fglrx_buggy_driver && !mesa_amd_buggy_driver && !intel_buggy_driver) found_GL_ARB_separate_shader_objects = true;
else fprintf(stderr, "Buggy driver detected, GL_ARB_separate_shader_objects will be disabled\n"
#ifdef __linux__
"Note the extension will be fixed on Mesa 11.2 or 11.1.2.\n"
#endif
"AMD proprietary driver => https://community.amd.com/thread/194895\n"
"If you want to try it, you can set the variable override_GL_ARB_separate_shader_objects to 1 in the ini file\n");
}
// GL4.2
if (ext.compare("GL_ARB_shading_language_420pack") == 0) found_GL_ARB_shading_language_420pack = true;
if (ext.compare("GL_ARB_texture_storage") == 0) found_GL_ARB_texture_storage = true;
if (ext.compare("GL_ARB_shader_image_load_store") == 0) found_GL_ARB_shader_image_load_store = true;
// GL4.3
if (ext.compare("GL_ARB_copy_image") == 0) found_GL_ARB_copy_image = true;
// GL4.4
if (ext.compare("GL_ARB_buffer_storage") == 0) found_GL_ARB_buffer_storage = true;
if (ext.compare("GL_ARB_clear_texture") == 0) found_GL_ARB_clear_texture = true;
// GL4.5
if (ext.compare("GL_ARB_direct_state_access") == 0) found_GL_ARB_direct_state_access = true;
if (ext.compare("GL_ARB_clip_control") == 0) found_GL_ARB_clip_control = true;
if (ext.compare("GL_ARB_texture_barrier") == 0) found_GL_ARB_texture_barrier = true;
//fprintf(stderr, "DEBUG ext: %s\n", ext.c_str());
}
}
bool status = true;
// Bonus
status &= status_and_override(found_GL_EXT_texture_filter_anisotropic, "GL_EXT_texture_filter_anisotropic");
// GL4.0
status &= status_and_override(found_GL_ARB_gpu_shader5, "GL_ARB_gpu_shader5");
status &= status_and_override(found_GL_ARB_draw_buffers_blend, "GL_ARB_draw_buffers_blend");
// GL4.1
status &= status_and_override(found_GL_ARB_viewport_array, "GL_ARB_viewport_array");
status &= status_and_override(found_GL_ARB_separate_shader_objects, "GL_ARB_separate_shader_objects");
// GL4.2
status &= status_and_override(found_GL_ARB_shader_image_load_store, "GL_ARB_shader_image_load_store");
status &= status_and_override(found_GL_ARB_shading_language_420pack, "GL_ARB_shading_language_420pack", true);
status &= status_and_override(found_GL_ARB_texture_storage, "GL_ARB_texture_storage", true);
// GL4.3
status &= status_and_override(found_GL_ARB_copy_image, "GL_ARB_copy_image");
// GL4.4
status &= status_and_override(found_GL_ARB_buffer_storage,"GL_ARB_buffer_storage");
status &= status_and_override(found_GL_ARB_clear_texture,"GL_ARB_clear_texture");
// GL4.5
status &= status_and_override(found_GL_ARB_clip_control, "GL_ARB_clip_control");
status &= status_and_override(found_GL_ARB_direct_state_access, "GL_ARB_direct_state_access");
status &= status_and_override(found_GL_ARB_texture_barrier, "GL_ARB_texture_barrier");
if (!found_GL_ARB_direct_state_access) {
Emulate_DSA::Init();
}
if (glBindTextureUnit == NULL) {
fprintf(stderr, "FATAL ERROR !!!! Failed to setup DSA function pointer!!!\n");
status = false;
}
if (!found_GL_ARB_texture_barrier) {
fprintf(stderr, "Error GL_ARB_texture_barrier is not supported by your driver. You can't emulate correctly the GS blending unit! Sorry!\n");
theApp.SetConfig("accurate_blending_unit", 0);
theApp.SetConfig("accurate_date", 0);
}
#ifdef _WIN32
if (status) {
if (intel_buggy_driver) {
fprintf(stderr, "OpenGL renderer isn't compatible with SandyBridge/IvyBridge GPU due to issues. Sorry.\n"
"Tip:Try it on Linux");
}
if (fglrx_buggy_driver) {
fprintf(stderr, "OpenGL renderer is slow on AMD GPU due to inefficient driver. Sorry.");
}
}
#endif
fprintf(stdout, "\n");
return status;
}
}

View File

@ -0,0 +1,370 @@
/*
* Copyright (C) 2011-2014 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#define GL_TEX_LEVEL_0 (0)
#define GL_TEX_LEVEL_1 (1)
#define GL_FB_DEFAULT (0)
#define GL_BUFFER_0 (0)
#ifndef GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR
#define GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR 0x00000008
#endif
// FIX compilation issue with Mesa 10
// Note it might be possible to do better with the right include
// in the rigth order but I don't have time
#ifndef APIENTRY
#define APIENTRY
#endif
#ifndef APIENTRYP
#define APIENTRYP APIENTRY *
#endif
// Mesa glext.h < 20150122 uses GLsizei for BUFFER*PROCs
#if GL_GLEXT_VERSION < 20150122
typedef GLsizei buffer_proc_t;
#else
typedef GLsizeiptr buffer_proc_t;
#endif
// Allow compilation with older mesa
#ifndef GL_VERSION_4_3
#define GL_VERSION_4_3 1
typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const void *userParam);
#endif
#ifndef GL_ARB_copy_image
#define GL_ARB_copy_image 1
#ifdef GL_GLEXT_PROTOTYPES
GLAPI void APIENTRY glCopyImageSubData (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
#endif /* GL_GLEXT_PROTOTYPES */
typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATAPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
#endif
#ifndef GL_VERSION_4_4
#define GL_VERSION_4_4 1
#define GL_MAX_VERTEX_ATTRIB_STRIDE 0x82E5
#define GL_MAP_PERSISTENT_BIT 0x0040
#define GL_MAP_COHERENT_BIT 0x0080
#define GL_DYNAMIC_STORAGE_BIT 0x0100
#define GL_CLIENT_STORAGE_BIT 0x0200
#define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT 0x00004000
#define GL_BUFFER_IMMUTABLE_STORAGE 0x821F
#define GL_BUFFER_STORAGE_FLAGS 0x8220
#define GL_CLEAR_TEXTURE 0x9365
#define GL_LOCATION_COMPONENT 0x934A
#define GL_TRANSFORM_FEEDBACK_BUFFER_INDEX 0x934B
#define GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE 0x934C
#define GL_QUERY_BUFFER 0x9192
#define GL_QUERY_BUFFER_BARRIER_BIT 0x00008000
#define GL_QUERY_BUFFER_BINDING 0x9193
#define GL_QUERY_RESULT_NO_WAIT 0x9194
#define GL_MIRROR_CLAMP_TO_EDGE 0x8743
typedef void (APIENTRYP PFNGLBUFFERSTORAGEPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);
typedef void (APIENTRYP PFNGLCLEARTEXIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data);
typedef void (APIENTRYP PFNGLCLEARTEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
typedef void (APIENTRYP PFNGLBINDBUFFERSBASEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers);
typedef void (APIENTRYP PFNGLBINDBUFFERSRANGEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes);
typedef void (APIENTRYP PFNGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);
typedef void (APIENTRYP PFNGLBINDSAMPLERSPROC) (GLuint first, GLsizei count, const GLuint *samplers);
typedef void (APIENTRYP PFNGLBINDIMAGETEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);
typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERSPROC) (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides);
#endif /* GL_VERSION_4_4 */
// Note: trim it
#ifndef GL_VERSION_4_5
#define GL_VERSION_4_5 1
#define GL_CONTEXT_LOST 0x0507
#define GL_NEGATIVE_ONE_TO_ONE 0x935E
#define GL_ZERO_TO_ONE 0x935F
#define GL_CLIP_ORIGIN 0x935C
#define GL_CLIP_DEPTH_MODE 0x935D
#define GL_QUERY_WAIT_INVERTED 0x8E17
#define GL_QUERY_NO_WAIT_INVERTED 0x8E18
#define GL_QUERY_BY_REGION_WAIT_INVERTED 0x8E19
#define GL_QUERY_BY_REGION_NO_WAIT_INVERTED 0x8E1A
#define GL_MAX_CULL_DISTANCES 0x82F9
#define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES 0x82FA
#define GL_TEXTURE_TARGET 0x1006
#define GL_QUERY_TARGET 0x82EA
#define GL_TEXTURE_BINDING 0x82EB
#define GL_GUILTY_CONTEXT_RESET 0x8253
#define GL_INNOCENT_CONTEXT_RESET 0x8254
#define GL_UNKNOWN_CONTEXT_RESET 0x8255
#define GL_RESET_NOTIFICATION_STRATEGY 0x8256
#define GL_LOSE_CONTEXT_ON_RESET 0x8252
#define GL_NO_RESET_NOTIFICATION 0x8261
#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT 0x00000004
#define GL_CONTEXT_RELEASE_BEHAVIOR 0x82FB
#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82FC
typedef void (APIENTRYP PFNGLCLIPCONTROLPROC) (GLenum origin, GLenum depth);
typedef void (APIENTRYP PFNGLCREATEBUFFERSPROC) (GLsizei n, GLuint *buffers);
typedef void (APIENTRYP PFNGLNAMEDBUFFERSTORAGEPROC) (GLuint buffer, GLsizei size, const void *data, GLbitfield flags);
typedef void (APIENTRYP PFNGLNAMEDBUFFERDATAPROC) (GLuint buffer, GLsizei size, const void *data, GLenum usage);
typedef void (APIENTRYP PFNGLNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizei size, const void *data);
typedef void (APIENTRYP PFNGLCOPYNAMEDBUFFERSUBDATAPROC) (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizei size);
typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERDATAPROC) (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data);
typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLenum internalformat, GLintptr offset, GLsizei size, GLenum format, GLenum type, const void *data);
typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFERPROC) (GLuint buffer, GLenum access);
typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFERRANGEPROC) (GLuint buffer, GLintptr offset, GLsizei length, GLbitfield access);
typedef GLboolean (APIENTRYP PFNGLUNMAPNAMEDBUFFERPROC) (GLuint buffer);
typedef void (APIENTRYP PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC) (GLuint buffer, GLintptr offset, GLsizei length);
typedef void (APIENTRYP PFNGLCREATEFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers);
typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC) (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC) (GLuint framebuffer, GLenum pname, GLint param);
typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level);
typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer);
typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC) (GLuint framebuffer, GLenum buf);
typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC) (GLuint framebuffer, GLsizei n, const GLenum *bufs);
typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC) (GLuint framebuffer, GLenum src);
typedef void (APIENTRYP PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC) (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments);
typedef void (APIENTRYP PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC) (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height);
typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERIVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint *value);
typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint *value);
typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERFVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat *value);
typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERFIPROC) (GLuint framebuffer, GLenum buffer, const GLfloat depth, GLint stencil);
typedef void (APIENTRYP PFNGLBLITNAMEDFRAMEBUFFERPROC) (GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
typedef GLenum (APIENTRYP PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC) (GLuint framebuffer, GLenum target);
typedef void (APIENTRYP PFNGLCREATERENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers);
typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEPROC) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (APIENTRYP PFNGLCREATETEXTURESPROC) (GLenum target, GLsizei n, GLuint *textures);
typedef void (APIENTRYP PFNGLTEXTUREBUFFERPROC) (GLuint texture, GLenum internalformat, GLuint buffer);
typedef void (APIENTRYP PFNGLTEXTUREBUFFERRANGEPROC) (GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizei size);
typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DPROC) (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFPROC) (GLuint texture, GLenum pname, GLfloat param);
typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFVPROC) (GLuint texture, GLenum pname, const GLfloat *param);
typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIPROC) (GLuint texture, GLenum pname, GLint param);
typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIIVPROC) (GLuint texture, GLenum pname, const GLint *params);
typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIUIVPROC) (GLuint texture, GLenum pname, const GLuint *params);
typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIVPROC) (GLuint texture, GLenum pname, const GLint *param);
typedef void (APIENTRYP PFNGLGENERATETEXTUREMIPMAPPROC) (GLuint texture);
typedef void (APIENTRYP PFNGLBINDTEXTUREUNITPROC) (GLuint unit, GLuint texture);
typedef void (APIENTRYP PFNGLCREATEVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays);
typedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYATTRIBPROC) (GLuint vaobj, GLuint index);
typedef void (APIENTRYP PFNGLENABLEVERTEXARRAYATTRIBPROC) (GLuint vaobj, GLuint index);
typedef void (APIENTRYP PFNGLVERTEXARRAYELEMENTBUFFERPROC) (GLuint vaobj, GLuint buffer);
typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBUFFERPROC) (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBUFFERSPROC) (GLuint vaobj, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides);
typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBBINDINGPROC) (GLuint vaobj, GLuint attribindex, GLuint bindingindex);
typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);
typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBIFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBLFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
typedef void (APIENTRYP PFNGLVERTEXARRAYBINDINGDIVISORPROC) (GLuint vaobj, GLuint bindingindex, GLuint divisor);
typedef void (APIENTRYP PFNGLGETVERTEXARRAYIVPROC) (GLuint vaobj, GLenum pname, GLint *param);
typedef void (APIENTRYP PFNGLGETVERTEXARRAYINDEXEDIVPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param);
typedef void (APIENTRYP PFNGLGETVERTEXARRAYINDEXED64IVPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint64 *param);
typedef void (APIENTRYP PFNGLCREATESAMPLERSPROC) (GLsizei n, GLuint *samplers);
typedef void (APIENTRYP PFNGLCREATEPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines);
typedef void (APIENTRYP PFNGLCREATEQUERIESPROC) (GLenum target, GLsizei n, GLuint *ids);
typedef void (APIENTRYP PFNGLMEMORYBARRIERBYREGIONPROC) (GLbitfield barriers);
typedef void (APIENTRYP PFNGLGETTEXTURESUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void *pixels);
typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void *pixels);
typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSPROC) (void);
typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint lod, GLsizei bufSize, void *pixels);
typedef void (APIENTRYP PFNGLGETNTEXIMAGEPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels);
typedef void (APIENTRYP PFNGLGETNUNIFORMDVPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params);
typedef void (APIENTRYP PFNGLGETNUNIFORMFVPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
typedef void (APIENTRYP PFNGLGETNUNIFORMIVPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
typedef void (APIENTRYP PFNGLGETNUNIFORMUIVPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params);
typedef void (APIENTRYP PFNGLREADNPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
typedef void (APIENTRYP PFNGLTEXTUREBARRIERPROC) (void);
typedef void (APIENTRYP PFNGLGETTEXTUREIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels);
#endif /* GL_VERSION_4_5 */
// Note: glActiveTexture & glBlendColor aren't included in the win GL ABI.
// (maybe gl.h is outdated, or my setup is wrong)
// Anyway, let's just keep the mangled function pointer for those 2 functions.
extern PFNGLACTIVETEXTUREPROC gl_ActiveTexture;
extern PFNGLBLENDCOLORPROC gl_BlendColor;
extern PFNGLATTACHSHADERPROC glAttachShader;
extern PFNGLBINDBUFFERPROC glBindBuffer;
extern PFNGLBINDBUFFERBASEPROC glBindBufferBase;
extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange;
extern PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
extern PFNGLBINDSAMPLERPROC glBindSampler;
extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
extern PFNGLBLENDEQUATIONSEPARATEIARBPROC glBlendEquationSeparateiARB;
extern PFNGLBLENDFUNCSEPARATEIARBPROC glBlendFuncSeparateiARB;
extern PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer;
extern PFNGLBUFFERDATAPROC glBufferData;
extern PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
extern PFNGLCLEARBUFFERFVPROC glClearBufferfv;
extern PFNGLCLEARBUFFERIVPROC glClearBufferiv;
extern PFNGLCLEARBUFFERUIVPROC glClearBufferuiv;
extern PFNGLCOMPILESHADERPROC glCompileShader;
extern PFNGLCOLORMASKIPROC glColorMaski;
extern PFNGLCREATEPROGRAMPROC glCreateProgram;
extern PFNGLCREATESHADERPROC glCreateShader;
extern PFNGLCREATESHADERPROGRAMVPROC glCreateShaderProgramv;
extern PFNGLDELETEBUFFERSPROC glDeleteBuffers;
extern PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers;
extern PFNGLDELETEPROGRAMPROC glDeleteProgram;
extern PFNGLDELETESAMPLERSPROC glDeleteSamplers;
extern PFNGLDELETESHADERPROC glDeleteShader;
extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
extern PFNGLDETACHSHADERPROC glDetachShader;
extern PFNGLDRAWBUFFERSPROC glDrawBuffers;
extern PFNGLDRAWELEMENTSBASEVERTEXPROC glDrawElementsBaseVertex;
extern PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
extern PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
extern PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
extern PFNGLGENBUFFERSPROC glGenBuffers;
extern PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
extern PFNGLGENSAMPLERSPROC glGenSamplers;
extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
extern PFNGLGETBUFFERPARAMETERIVPROC glGetBufferParameteriv;
extern PFNGLGETDEBUGMESSAGELOGARBPROC glGetDebugMessageLogARB;
extern PFNGLDEBUGMESSAGECALLBACKPROC glDebugMessageCallback;
extern PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
extern PFNGLGETPROGRAMIVPROC glGetProgramiv;
extern PFNGLGETSHADERIVPROC glGetShaderiv;
extern PFNGLGETSTRINGIPROC glGetStringi;
extern PFNGLISFRAMEBUFFERPROC glIsFramebuffer;
extern PFNGLLINKPROGRAMPROC glLinkProgram;
extern PFNGLMAPBUFFERPROC glMapBuffer;
extern PFNGLMAPBUFFERRANGEPROC glMapBufferRange;
extern PFNGLPROGRAMPARAMETERIPROC glProgramParameteri;
extern PFNGLSAMPLERPARAMETERFPROC glSamplerParameterf;
extern PFNGLSAMPLERPARAMETERIPROC glSamplerParameteri;
extern PFNGLSHADERSOURCEPROC glShaderSource;
extern PFNGLUNIFORM1IPROC glUniform1i;
extern PFNGLUNMAPBUFFERPROC glUnmapBuffer;
extern PFNGLUSEPROGRAMSTAGESPROC glUseProgramStages;
extern PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer;
extern PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
extern PFNGLBUFFERSUBDATAPROC glBufferSubData;
extern PFNGLFENCESYNCPROC glFenceSync;
extern PFNGLDELETESYNCPROC glDeleteSync;
extern PFNGLCLIENTWAITSYNCPROC glClientWaitSync;
extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange;
extern PFNGLBLENDEQUATIONSEPARATEPROC glBlendEquationSeparate;
extern PFNGLBLENDFUNCSEPARATEPROC glBlendFuncSeparate;
// Query object
extern PFNGLBEGINQUERYPROC glBeginQuery;
extern PFNGLENDQUERYPROC glEndQuery;
extern PFNGLGETQUERYIVPROC glGetQueryiv;
extern PFNGLGETQUERYOBJECTIVPROC glGetQueryObjectiv;
extern PFNGLGETQUERYOBJECTUIVPROC glGetQueryObjectuiv;
extern PFNGLQUERYCOUNTERPROC glQueryCounter;
extern PFNGLGETQUERYOBJECTI64VPROC glGetQueryObjecti64v;
extern PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v;
extern PFNGLGETINTEGER64VPROC glGetInteger64v;
// GL4.0
// GL4.1
extern PFNGLBINDPROGRAMPIPELINEPROC glBindProgramPipeline;
extern PFNGLDELETEPROGRAMPIPELINESPROC glDeleteProgramPipelines;
extern PFNGLGENPROGRAMPIPELINESPROC glGenProgramPipelines;
extern PFNGLGETPROGRAMPIPELINEIVPROC glGetProgramPipelineiv;
extern PFNGLVALIDATEPROGRAMPIPELINEPROC glValidateProgramPipeline;
extern PFNGLGETPROGRAMPIPELINEINFOLOGPROC glGetProgramPipelineInfoLog;
extern PFNGLGETPROGRAMBINARYPROC glGetProgramBinary;
extern PFNGLVIEWPORTINDEXEDFPROC glViewportIndexedf;
extern PFNGLVIEWPORTINDEXEDFVPROC glViewportIndexedfv;
extern PFNGLSCISSORINDEXEDPROC glScissorIndexed;
extern PFNGLSCISSORINDEXEDVPROC glScissorIndexedv;
// NO GL4.1
extern PFNGLUSEPROGRAMPROC glUseProgram;
extern PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
extern PFNGLPROGRAMUNIFORM1IPROC glProgramUniform1i;
// GL4.2
extern PFNGLBINDIMAGETEXTUREPROC glBindImageTexture;
extern PFNGLMEMORYBARRIERPROC glMemoryBarrier;
extern PFNGLTEXSTORAGE2DPROC glTexStorage2D;
extern PFNGLPOPDEBUGGROUPPROC glPopDebugGroup;
// GL4.3
extern PFNGLCOPYIMAGESUBDATAPROC glCopyImageSubData;
extern PFNGLINVALIDATETEXIMAGEPROC glInvalidateTexImage;
extern PFNGLPUSHDEBUGGROUPPROC glPushDebugGroup;
extern PFNGLDEBUGMESSAGEINSERTPROC glDebugMessageInsert;
extern PFNGLDEBUGMESSAGECONTROLPROC glDebugMessageControl;
// GL4.4
extern PFNGLCLEARTEXIMAGEPROC glClearTexImage;
extern PFNGLBUFFERSTORAGEPROC glBufferStorage;
// GL4.5
extern PFNGLCREATETEXTURESPROC glCreateTextures;
extern PFNGLTEXTURESTORAGE2DPROC glTextureStorage2D;
extern PFNGLTEXTURESUBIMAGE2DPROC glTextureSubImage2D;
extern PFNGLCOPYTEXTURESUBIMAGE2DPROC glCopyTextureSubImage2D;
extern PFNGLBINDTEXTUREUNITPROC glBindTextureUnit;
extern PFNGLGETTEXTUREIMAGEPROC glGetTextureImage;
extern PFNGLTEXTUREPARAMETERIPROC glTextureParameteri;
extern PFNGLCREATEFRAMEBUFFERSPROC glCreateFramebuffers;
extern PFNGLCLEARNAMEDFRAMEBUFFERFVPROC glClearNamedFramebufferfv;
extern PFNGLCLEARNAMEDFRAMEBUFFERIVPROC glClearNamedFramebufferiv;
extern PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC glClearNamedFramebufferuiv;
extern PFNGLNAMEDFRAMEBUFFERTEXTUREPROC glNamedFramebufferTexture;
extern PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC glNamedFramebufferDrawBuffers;
extern PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC glNamedFramebufferReadBuffer;
extern PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC glCheckNamedFramebufferStatus;
extern PFNGLCREATEBUFFERSPROC glCreateBuffers;
extern PFNGLNAMEDBUFFERSTORAGEPROC glNamedBufferStorage;
extern PFNGLNAMEDBUFFERDATAPROC glNamedBufferData;
extern PFNGLNAMEDBUFFERSUBDATAPROC glNamedBufferSubData;
extern PFNGLMAPNAMEDBUFFERPROC glMapNamedBuffer;
extern PFNGLMAPNAMEDBUFFERRANGEPROC glMapNamedBufferRange;
extern PFNGLUNMAPNAMEDBUFFERPROC glUnmapNamedBuffer;
extern PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC glFlushMappedNamedBufferRange;
extern PFNGLCREATESAMPLERSPROC glCreateSamplers;
extern PFNGLCREATEPROGRAMPIPELINESPROC glCreateProgramPipelines;
extern PFNGLCLIPCONTROLPROC glClipControl;
extern PFNGLTEXTUREBARRIERPROC glTextureBarrier;
namespace Emulate_DSA {
extern void SetFramebufferTarget(GLenum target);
extern void SetBufferTarget(GLenum target);
extern void Init();
}
namespace GLLoader {
bool check_gl_version(int major, int minor);
void init_gl_function();
bool check_gl_supported_extension();
extern bool fglrx_buggy_driver;
extern bool mesa_amd_buggy_driver;
extern bool nvidia_buggy_driver;
extern bool intel_buggy_driver;
extern bool in_replayer;
// GL
extern bool found_GL_ARB_separate_shader_objects;
extern bool found_GL_ARB_copy_image;
extern bool found_geometry_shader;
extern bool found_GL_ARB_gpu_shader5;
extern bool found_GL_ARB_shader_image_load_store;
extern bool found_GL_ARB_clear_texture;
extern bool found_GL_ARB_buffer_storage;
extern bool found_GL_ARB_clip_control;
extern bool found_GL_ARB_direct_state_access;
extern bool found_GL_ARB_texture_barrier;
extern bool found_GL_EXT_texture_filter_anisotropic;
}

View File

@ -0,0 +1,97 @@
/*
* Copyright (C) 2011-2013 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GLState.h"
namespace GLState {
GLuint fbo;
GSVector2i viewport;
GSVector4i scissor;
bool blend;
uint16 eq_RGB;
uint16 f_sRGB;
uint16 f_dRGB;
uint8 bf;
uint32 wrgba;
bool depth;
GLenum depth_func;
bool depth_mask;
bool stencil;
GLenum stencil_func;
GLenum stencil_pass;
GLuint ubo;
GLuint ps_ss;
GLuint rt;
GLuint ds;
GLuint tex_unit[4];
GLuint64 tex_handle[4];
GLuint ps;
GLuint gs;
GLuint vs;
GLuint program;
bool dirty_prog;
void Clear() {
fbo = 0;
viewport = GSVector2i(0, 0);
scissor = GSVector4i(0, 0, 0, 0);
blend = false;
eq_RGB = 0;
f_sRGB = 0;
f_dRGB = 0;
bf = 0;
wrgba = 0xF;
depth = false;
depth_func = 0;
depth_mask = false;
stencil = false;
stencil_func = 0;
stencil_pass = 0;
ubo = 0;
ps_ss = 0;
rt = 0;
ds = 0;
for (size_t i = 0; i < countof(tex_unit); i++)
tex_unit[i] = 0;
for (size_t i = 0; i < countof(tex_handle); i++)
tex_handle[i] = 0;
ps = 0;
gs = 0;
vs = 0;
program = 0;
dirty_prog = true;
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright (C) 2011-2013 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSdx.h"
#include "GSVector.h"
namespace GLState {
extern GLuint fbo; // frame buffer object
extern GSVector2i viewport;
extern GSVector4i scissor;
extern bool blend;
extern uint16 eq_RGB;
extern uint16 f_sRGB;
extern uint16 f_dRGB;
extern uint8 bf;
extern uint32 wrgba;
extern bool depth;
extern GLenum depth_func;
extern bool depth_mask;
extern bool stencil;
extern GLenum stencil_func;
extern GLenum stencil_pass;
extern GLuint ubo; // uniform buffer object
extern GLuint ps_ss; // sampler
extern GLuint rt; // render target
extern GLuint ds; // Depth-Stencil
extern GLuint tex_unit[4]; // shader input texture
extern GLuint64 tex_handle[4]; // shader input texture
extern GLuint ps;
extern GLuint gs;
extern GLuint vs;
extern GLuint program; // monolith program (when sso isn't supported)
extern bool dirty_prog;
extern void Clear();
}

310
plugins/GSdx_legacy/GPU.cpp Normal file
View File

@ -0,0 +1,310 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSdx.h"
#include "GSUtil.h"
#include "GPURendererSW.h"
#include "GSDeviceNull.h"
#ifdef _WIN32
#include "GPUSettingsDlg.h"
#include "GSDevice9.h"
#include "GSDevice11.h"
static HRESULT s_hr = E_FAIL;
#endif
#define PSE_LT_GPU 2
static GPURenderer* s_gpu = NULL;
EXPORT_C_(uint32) PSEgetLibType()
{
return PSE_LT_GPU;
}
EXPORT_C_(const char*) PSEgetLibName()
{
return GSUtil::GetLibName();
}
EXPORT_C_(uint32) PSEgetLibVersion()
{
static const uint32 version = 1;
static const uint32 revision = 1;
return version << 16 | revision << 8 | PLUGIN_VERSION;
}
EXPORT_C_(int32) GPUinit()
{
return 0;
}
EXPORT_C_(int32) GPUshutdown()
{
return 0;
}
EXPORT_C_(int32) GPUclose()
{
delete s_gpu;
s_gpu = NULL;
#ifdef _WIN32
if(SUCCEEDED(s_hr))
{
::CoUninitialize();
s_hr = E_FAIL;
}
#endif
return 0;
}
EXPORT_C_(int32) GPUopen(void* hWnd)
{
GPUclose();
if(!GSUtil::CheckSSE())
{
return -1;
}
#ifdef _WIN32
s_hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
if(!GSUtil::CheckDirectX())
{
return -1;
}
#endif
int renderer = theApp.GetConfig("Renderer", 1);
int threads = theApp.GetConfig("extrathreads", DEFAULT_EXTRA_RENDERING_THREADS);
switch(renderer)
{
default:
#ifdef _WIN32
case 0: s_gpu = new GPURendererSW(new GSDevice9(), threads); break;
case 1: s_gpu = new GPURendererSW(new GSDevice11(), threads); break;
#endif
case 3: s_gpu = new GPURendererSW(new GSDeviceNull(), threads); break;
//case 4: s_gpu = new GPURendererNull(new GSDeviceNull()); break;
}
if(!s_gpu->Create(hWnd))
{
GPUclose();
return -1;
}
return 0;
}
EXPORT_C_(int32) GPUconfigure()
{
#ifdef _WIN32
GPUSettingsDlg dlg;
if(IDOK == dlg.DoModal())
{
GPUshutdown();
GPUinit();
}
#else
// TODO: linux
#endif
return 0;
}
EXPORT_C_(int32) GPUtest()
{
return 0;
}
EXPORT_C GPUabout()
{
// TODO
}
EXPORT_C GPUwriteDataMem(const uint8* mem, uint32 size)
{
s_gpu->WriteData(mem, size);
}
EXPORT_C GPUwriteData(uint32 data)
{
s_gpu->WriteData((uint8*)&data, 1);
}
EXPORT_C GPUreadDataMem(uint8* mem, uint32 size)
{
s_gpu->ReadData(mem, size);
}
EXPORT_C_(uint32) GPUreadData()
{
uint32 data = 0;
s_gpu->ReadData((uint8*)&data, 1);
return data;
}
EXPORT_C GPUwriteStatus(uint32 status)
{
s_gpu->WriteStatus(status);
}
EXPORT_C_(uint32) GPUreadStatus()
{
return s_gpu->ReadStatus();
}
EXPORT_C_(uint32) GPUdmaChain(const uint8* mem, uint32 addr)
{
uint32 last[3];
memset(last, 0xff, sizeof(last));
do
{
if(addr == last[1] || addr == last[2])
{
break;
}
(addr < last[0] ? last[1] : last[2]) = addr;
last[0] = addr;
uint8 size = mem[addr + 3];
if(size > 0)
{
s_gpu->WriteData(&mem[addr + 4], size);
}
addr = *(uint32*)&mem[addr] & 0xffffff;
}
while(addr != 0xffffff);
return 0;
}
EXPORT_C_(uint32) GPUgetMode()
{
// TODO
return 0;
}
EXPORT_C GPUsetMode(uint32 mode)
{
// TODO
}
EXPORT_C GPUupdateLace()
{
s_gpu->VSync();
}
EXPORT_C GPUmakeSnapshot()
{
s_gpu->MakeSnapshot("c:/"); // TODO
}
EXPORT_C GPUdisplayText(char* text)
{
// TODO
}
EXPORT_C GPUdisplayFlags(uint32 flags)
{
// TODO
}
EXPORT_C_(int32) GPUfreeze(uint32 type, GPUFreezeData* data)
{
if(!data || data->version != 1)
{
return 0;
}
if(type == 0)
{
s_gpu->Defrost(data);
return 1;
}
else if(type == 1)
{
s_gpu->Freeze(data);
return 1;
}
else if(type == 2)
{
int slot = *(int*)data + 1;
if(slot < 1 || slot > 9)
{
return 0;
}
// TODO
return 1;
}
return 0;
}
EXPORT_C GPUgetScreenPic(uint8* mem)
{
// TODO
}
EXPORT_C GPUshowScreenPic(uint8* mem)
{
// TODO
}
EXPORT_C GPUcursor(int player, int x, int y)
{
// TODO
}

276
plugins/GSdx_legacy/GPU.h Normal file
View File

@ -0,0 +1,276 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#pragma pack(push, 1)
#include "GS.h"
enum
{
GPU_POLYGON = 1,
GPU_LINE = 2,
GPU_SPRITE = 3,
};
REG32_(GPUReg, STATUS)
uint32 TX:4;
uint32 TY:1;
uint32 ABR:2;
uint32 TP:2;
uint32 DTD:1;
uint32 DFE:1;
uint32 MD:1;
uint32 ME:1;
uint32 _PAD0:3;
uint32 WIDTH1:1;
uint32 WIDTH0:2;
uint32 HEIGHT:1;
uint32 ISPAL:1;
uint32 ISRGB24:1;
uint32 ISINTER:1;
uint32 DEN:1;
uint32 _PAD1:2;
uint32 IDLE:1;
uint32 IMG:1;
uint32 COM:1;
uint32 DMA:2;
uint32 LCF:1;
/*
uint32 TX:4;
uint32 TY:1;
uint32 ABR:2;
uint32 TP:2;
uint32 DTD:1;
uint32 DFE:1;
uint32 PBW:1;
uint32 PBC:1;
uint32 _PAD0:3;
uint32 HRES2:1;
uint32 HRES1:2;
uint32 VRES:1;
uint32 ISPAL:1;
uint32 ISRGB24:1;
uint32 ISINTER:1;
uint32 ISSTOP:1;
uint32 _PAD1:1;
uint32 DMARDY:1;
uint32 IDIDLE:1;
uint32 DATARDY:1;
uint32 ISEMPTY:1;
uint32 TMODE:2;
uint32 ODE:1;
*/
REG_END
REG32_(GPUReg, PACKET)
uint32 _PAD:24;
uint32 OPTION:5;
uint32 TYPE:3;
REG_END
REG32_(GPUReg, PRIM)
uint32 VTX:24;
uint32 TGE:1;
uint32 ABE:1;
uint32 TME:1;
uint32 _PAD2:1;
uint32 IIP:1;
uint32 TYPE:3;
REG_END
REG32_(GPUReg, POLYGON)
uint32 _PAD:24;
uint32 TGE:1;
uint32 ABE:1;
uint32 TME:1;
uint32 VTX:1;
uint32 IIP:1;
uint32 TYPE:3;
REG_END
REG32_(GPUReg, LINE)
uint32 _PAD:24;
uint32 ZERO1:1;
uint32 ABE:1;
uint32 ZERO2:1;
uint32 PLL:1;
uint32 IIP:1;
uint32 TYPE:3;
REG_END
REG32_(GPUReg, SPRITE)
uint32 _PAD:24;
uint32 ZERO:1;
uint32 ABE:1;
uint32 TME:1;
uint32 SIZE:2;
uint32 TYPE:3;
REG_END
REG32_(GPUReg, RESET)
uint32 _PAD:32;
REG_END
REG32_(GPUReg, DEN)
uint32 DEN:1;
uint32 _PAD:31;
REG_END
REG32_(GPUReg, DMA)
uint32 DMA:2;
uint32 _PAD:30;
REG_END
REG32_(GPUReg, DAREA)
uint32 X:10;
uint32 Y:9;
uint32 _PAD:13;
REG_END
REG32_(GPUReg, DHRANGE)
uint32 X1:12;
uint32 X2:12;
uint32 _PAD:8;
REG_END
REG32_(GPUReg, DVRANGE)
uint32 Y1:10;
uint32 Y2:11;
uint32 _PAD:11;
REG_END
REG32_(GPUReg, DMODE)
uint32 WIDTH0:2;
uint32 HEIGHT:1;
uint32 ISPAL:1;
uint32 ISRGB24:1;
uint32 ISINTER:1;
uint32 WIDTH1:1;
uint32 REVERSE:1;
uint32 _PAD:24;
REG_END
REG32_(GPUReg, GPUINFO)
uint32 PARAM:24;
uint32 _PAD:8;
REG_END
REG32_(GPUReg, MODE)
uint32 TX:4;
uint32 TY:1;
uint32 ABR:2;
uint32 TP:2;
uint32 DTD:1;
uint32 DFE:1;
uint32 _PAD:21;
REG_END
REG32_(GPUReg, MASK)
uint32 MD:1;
uint32 ME:1;
uint32 _PAD:30;
REG_END
REG32_(GPUReg, DRAREA)
uint32 X:10;
uint32 Y:10;
uint32 _PAD:12;
REG_END
REG32_(GPUReg, DROFF)
int32 X:11;
int32 Y:11;
int32 _PAD:10;
REG_END
REG32_(GPUReg, RGB)
uint32 R:8;
uint32 G:8;
uint32 B:8;
uint32 _PAD:8;
REG_END
REG32_(GPUReg, XY)
int32 X:11;
int32 _PAD1:5;
int32 Y:11;
int32 _PAD2:5;
REG_END
REG32_(GPUReg, UV)
uint32 U:8;
uint32 V:8;
uint32 _PAD:16;
REG_END
REG32_(GPUReg, TWIN)
uint32 TWW:5;
uint32 TWH:5;
uint32 TWX:5;
uint32 TWY:5;
uint32 _PAD:12;
REG_END
REG32_(GPUReg, CLUT)
uint32 _PAD1:16;
uint32 X:6;
uint32 Y:9;
uint32 _PAD2:1;
REG_END
REG32_SET(GPUReg)
GPURegSTATUS STATUS;
GPURegPACKET PACKET;
GPURegPRIM PRIM;
GPURegPOLYGON POLYGON;
GPURegLINE LINE;
GPURegSPRITE SPRITE;
GPURegRESET RESET;
GPURegDEN DEN;
GPURegDMA DMA;
GPURegDAREA DAREA;
GPURegDHRANGE DHRANGE;
GPURegDVRANGE DVRANGE;
GPURegDMODE DMODE;
GPURegGPUINFO GPUINFO;
GPURegMODE MODE;
GPURegMASK MASK;
GPURegDRAREA DRAREA;
GPURegDROFF DROFF;
GPURegRGB RGB;
GPURegXY XY;
GPURegUV UV;
GPURegTWIN TWIN;
GPURegCLUT CLUT;
REG_SET_END
struct GPUFreezeData
{
uint32 version; // == 1
uint32 status;
uint32 control[256];
uint16 vram[1024 * 1024];
};
#pragma pack(pop)

View File

@ -0,0 +1,495 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GPUDrawScanline.h"
GPUDrawScanline::GPUDrawScanline()
: m_sp_map("GPUSetupPrim", &m_local)
, m_ds_map("GPUDrawScanline", &m_local)
{
memset(&m_local, 0, sizeof(m_local));
m_local.gd = &m_global;
}
GPUDrawScanline::~GPUDrawScanline()
{
}
void GPUDrawScanline::BeginDraw(const GSRasterizerData* data)
{
memcpy(&m_global, &((const SharedData*)data)->global, sizeof(m_global));
if(m_global.sel.tme && m_global.sel.twin)
{
uint32 u, v;
u = ~(m_global.twin.x << 3) & 0xff; // TWW
v = ~(m_global.twin.y << 3) & 0xff; // TWH
m_local.twin[0].u = GSVector4i((u << 16) | u);
m_local.twin[0].v = GSVector4i((v << 16) | v);
u = m_global.twin.z << 3; // TWX
v = m_global.twin.w << 3; // TWY
m_local.twin[1].u = GSVector4i((u << 16) | u) & ~m_local.twin[0].u;
m_local.twin[1].v = GSVector4i((v << 16) | v) & ~m_local.twin[0].v;
}
m_ds = m_ds_map[m_global.sel];
m_de = NULL;
m_dr = NULL; // TODO
// doesn't need all bits => less functions generated
GPUScanlineSelector sel;
sel.key = 0;
sel.iip = m_global.sel.iip;
sel.tfx = m_global.sel.tfx;
sel.twin = m_global.sel.twin;
sel.sprite = m_global.sel.sprite;
m_sp = m_sp_map[sel];
}
void GPUDrawScanline::EndDraw(uint64 frame, uint64 ticks, int actual, int total)
{
m_ds_map.UpdateStats(frame, ticks, actual, total);
}
#ifndef ENABLE_JIT_RASTERIZER
void GPUDrawScanline::SetupPrim(const GSVertexSW* vertex, const uint32* index, const GSVertexSW& dscan)
{
GPUScanlineSelector sel = m_global.sel;
const GSVector4* shift = GPUSetupPrimCodeGenerator::m_shift;
if(sel.tme && !sel.twin)
{
if(sel.sprite)
{
GSVector4i t = (GSVector4i(vertex[index[1]].t) >> 8) - GSVector4i::x00000001();
t = t.ps32(t);
t = t.upl16(t);
m_local.twin[2].u = t.xxxx();
m_local.twin[2].v = t.yyyy();
}
else
{
// TODO: not really needed
m_local.twin[2].u = GSVector4i::x00ff();
m_local.twin[2].v = GSVector4i::x00ff();
}
}
if(sel.tme || sel.iip && sel.tfx != 3)
{
GSVector4 dt = dscan.t;
GSVector4 dc = dscan.c;
GSVector4i dtc8 = GSVector4i(dt * shift[0]).ps32(GSVector4i(dc * shift[0]));
if(sel.tme)
{
m_local.d8.st = dtc8.upl16(dtc8);
}
if(sel.iip && sel.tfx != 3)
{
m_local.d8.c = dtc8.uph16(dtc8);
}
if(sel.tme)
{
GSVector4 dtx = dt.xxxx();
GSVector4 dty = dt.yyyy();
m_local.d.s = GSVector4i(dtx * shift[1]).ps32(GSVector4i(dtx * shift[2]));
m_local.d.t = GSVector4i(dty * shift[1]).ps32(GSVector4i(dty * shift[2]));
}
if(sel.iip && sel.tfx != 3)
{
GSVector4 dcx = dc.xxxx();
GSVector4 dcy = dc.yyyy();
GSVector4 dcz = dc.zzzz();
m_local.d.r = GSVector4i(dcx * shift[1]).ps32(GSVector4i(dcx * shift[2]));
m_local.d.g = GSVector4i(dcy * shift[1]).ps32(GSVector4i(dcy * shift[2]));
m_local.d.b = GSVector4i(dcz * shift[1]).ps32(GSVector4i(dcz * shift[2]));
}
}
}
void GPUDrawScanline::DrawScanline(int pixels, int left, int top, const GSVertexSW& scan)
{
// TODO: not tested yet, probably bogus
GPUScanlineSelector sel = m_global.sel;
GSVector4i s, t;
GSVector4i uf, vf;
GSVector4i rf, gf, bf;
GSVector4i dither;
// Init
uint16* fb = (uint16*)m_global.vm + (top << (10 + sel.scalex)) + left;
int steps = pixels - 8;
if(sel.dtd)
{
dither = GSVector4i::load<false>(&GPUDrawScanlineCodeGenerator::m_dither[top & 3][left & 3]);
}
if(sel.tme)
{
GSVector4i vt = GSVector4i(scan.t).xxzzl();
s = vt.xxxx().add16(m_local.d.s);
t = vt.yyyy();
if(!sel.sprite)
{
t = t.add16(m_local.d.t);
}
else
{
if(sel.ltf)
{
vf = t.sll16(1).srl16(1);
}
}
}
if(sel.tfx != 3)
{
GSVector4i vc = GSVector4i(scan.c).xxzzlh();
rf = vc.xxxx();
gf = vc.yyyy();
bf = vc.zzzz();
if(sel.iip)
{
rf = rf.add16(m_local.d.r);
gf = gf.add16(m_local.d.g);
bf = bf.add16(m_local.d.b);
}
}
while(1)
{
do
{
GSVector4i test = GPUDrawScanlineCodeGenerator::m_test[7 + (steps & (steps >> 31))];
GSVector4i fd = GSVector4i::load(fb, fb + 8);
GSVector4i r, g, b, a;
// TestMask
if(sel.me)
{
test |= fd.sra16(15);
if(test.alltrue()) continue;
}
// SampleTexture
if(sel.tme)
{
GSVector4i u0, v0, u1, v1;
GSVector4i addr00, addr01, addr10, addr11;
GSVector4i c00, c01, c10, c11;
if(sel.ltf)
{
u0 = s.sub16(GSVector4i(0x00200020)); // - 0.125f
v0 = t.sub16(GSVector4i(0x00200020)); // - 0.125f
uf = u0.sll16(8).srl16(1);
vf = v0.sll16(8).srl16(1);;
}
else
{
u0 = s;
v0 = t;
}
u0 = u0.srl16(8);
v0 = v0.srl16(8);
if(sel.ltf)
{
u1 = u0.add16(GSVector4i::x0001());
v1 = v0.add16(GSVector4i::x0001());
if(sel.twin)
{
u0 = (u0 & m_local.twin[0].u).add16(m_local.twin[1].u);
v0 = (v0 & m_local.twin[0].v).add16(m_local.twin[1].v);
u1 = (u1 & m_local.twin[0].u).add16(m_local.twin[1].u);
v1 = (v1 & m_local.twin[0].v).add16(m_local.twin[1].v);
}
else
{
u0 = u0.min_i16(m_local.twin[2].u);
v0 = v0.min_i16(m_local.twin[2].v);
u1 = u1.min_i16(m_local.twin[2].u);
v1 = v1.min_i16(m_local.twin[2].v);
}
addr00 = v0.sll16(8) | u0;
addr01 = v0.sll16(8) | u1;
addr10 = v1.sll16(8) | u0;
addr11 = v1.sll16(8) | u1;
// TODO
if(sel.tlu)
{
c00 = addr00.gather16_16((const uint16*)m_global.vm, m_global.clut);
c01 = addr01.gather16_16((const uint16*)m_global.vm, m_global.clut);
c10 = addr10.gather16_16((const uint16*)m_global.vm, m_global.clut);
c11 = addr11.gather16_16((const uint16*)m_global.vm, m_global.clut);
}
else
{
c00 = addr00.gather16_16((const uint16*)m_global.vm);
c01 = addr01.gather16_16((const uint16*)m_global.vm);
c10 = addr10.gather16_16((const uint16*)m_global.vm);
c11 = addr11.gather16_16((const uint16*)m_global.vm);
}
GSVector4i r00 = c00.sll16(11).srl16(8);
GSVector4i r01 = c01.sll16(11).srl16(8);
GSVector4i r10 = c10.sll16(11).srl16(8);
GSVector4i r11 = c11.sll16(11).srl16(8);
r00 = r00.lerp16<0>(r01, uf);
r10 = r10.lerp16<0>(r11, uf);
GSVector4i g00 = c00.sll16(6).srl16(11).sll16(3);
GSVector4i g01 = c01.sll16(6).srl16(11).sll16(3);
GSVector4i g10 = c10.sll16(6).srl16(11).sll16(3);
GSVector4i g11 = c11.sll16(6).srl16(11).sll16(3);
g00 = g00.lerp16<0>(g01, uf);
g10 = g10.lerp16<0>(g11, uf);
GSVector4i b00 = c00.sll16(1).srl16(11).sll16(3);
GSVector4i b01 = c01.sll16(1).srl16(11).sll16(3);
GSVector4i b10 = c10.sll16(1).srl16(11).sll16(3);
GSVector4i b11 = c11.sll16(1).srl16(11).sll16(3);
b00 = b00.lerp16<0>(b01, uf);
b10 = b10.lerp16<0>(b11, uf);
GSVector4i a00 = c00.sra16(15).sll16(8);
GSVector4i a01 = c01.sra16(15).sll16(8);
GSVector4i a10 = c10.sra16(15).sll16(8);
GSVector4i a11 = c11.sra16(15).sll16(8);
a00 = a00.lerp16<0>(a01, uf);
a10 = a10.lerp16<0>(a11, uf);
r = r00.lerp16<0>(r10, vf);
g = g00.lerp16<0>(g10, vf);
b = b00.lerp16<0>(b10, vf);
a = a00.lerp16<0>(a10, vf);
test |= (r | g | b | a).eq16(GSVector4i::zero()); // mask out blank pixels (not perfect)
a = a.gt16(GSVector4i::zero());
}
else
{
if(sel.twin)
{
u0 = (u0 & m_local.twin[0].u).add16(m_local.twin[1].u);
v0 = (v0 & m_local.twin[0].v).add16(m_local.twin[1].v);
}
else
{
u0 = u0.min_i16(m_local.twin[2].u);
v0 = v0.min_i16(m_local.twin[2].v);
}
addr00 = v0.sll16(8) | u0;
// TODO
if(sel.tlu)
{
c00 = addr00.gather16_16((const uint16*)m_global.vm, m_global.clut);
}
else
{
c00 = addr00.gather16_16((const uint16*)m_global.vm);
}
r = (c00 << 3) & 0x00f800f8;
g = (c00 >> 2) & 0x00f800f8;
b = (c00 >> 7) & 0x00f800f8;
a = c00.sra16(15);
test |= c00.eq16(GSVector4i::zero()); // mask out blank pixels
}
}
// ColorTFX
switch(sel.tfx)
{
case 0: // none (tfx = 0)
case 1: // none (tfx = tge)
r = rf.srl16(7);
g = gf.srl16(7);
b = bf.srl16(7);
break;
case 2: // modulate (tfx = tme | tge)
r = r.modulate16<1>(rf).clamp8();
g = g.modulate16<1>(gf).clamp8();
b = b.modulate16<1>(bf).clamp8();
break;
case 3: // decal (tfx = tme)
break;
default:
__assume(0);
}
// AlphaBlend
if(sel.abe)
{
GSVector4i rs = r;
GSVector4i gs = g;
GSVector4i bs = b;
GSVector4i rd = (fd & 0x001f001f) << 3;
GSVector4i gd = (fd & 0x03e003e0) >> 2;
GSVector4i bd = (fd & 0x7c007c00) >> 7;
switch(sel.abr)
{
case 0:
r = rd.avg8(rs);
g = gd.avg8(gs);
b = bd.avg8(bs);
break;
case 1:
r = rd.addus8(rs);
g = gd.addus8(gs);
b = bd.addus8(bs);
break;
case 2:
r = rd.subus8(rs);
g = gd.subus8(gs);
b = bd.subus8(bs);
break;
case 3:
r = rd.addus8(rs.srl16(2));
g = gd.addus8(gs.srl16(2));
b = bd.addus8(bs.srl16(2));
break;
default:
__assume(0);
}
if(sel.tme)
{
r = rs.blend8(rd, a);
g = gs.blend8(gd, a);
b = bs.blend8(bd, a);
}
}
// Dither
if(sel.dtd)
{
r = r.addus8(dither);
g = g.addus8(dither);
b = b.addus8(dither);
}
// WriteFrame
GSVector4i fs = r | g | b | (sel.md ? GSVector4i(0x80008000) : sel.tme ? a : GSVector4i::zero());
fs = fs.blend8(fd, test);
GSVector4i::store(fb, fb + 8, fs);
}
while(0);
if(steps <= 0) break;
steps -= 8;
fb += 8;
if(sel.tme)
{
GSVector4i st = m_local.d8.st;
s = s.add16(st.xxxx());
t = t.add16(st.yyyy());
}
if(sel.tfx != 3) // != decal
{
if(sel.iip)
{
GSVector4i c = m_local.d8.c;
rf = rf.add16(c.xxxx());
gf = gf.add16(c.yyyy());
bf = bf.add16(c.zzzz());
}
}
}
}
void GPUDrawScanline::DrawEdge(int pixels, int left, int top, const GSVertexSW& scan)
{
ASSERT(0);
}
void GPUDrawScanline::DrawRect(const GSVector4i& r, const GSVertexSW& v)
{
// TODO
}
#endif

View File

@ -0,0 +1,76 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GPUState.h"
#include "GSRasterizer.h"
#include "GPUScanlineEnvironment.h"
#include "GPUSetupPrimCodeGenerator.h"
#include "GPUDrawScanlineCodeGenerator.h"
class GPUDrawScanline : public IDrawScanline
{
public:
class SharedData : public GSRasterizerData
{
public:
GPUScanlineGlobalData global;
public:
SharedData()
{
global.clut = NULL;
}
virtual ~SharedData()
{
if(global.clut) _aligned_free(global.clut);
}
};
protected:
GPUScanlineGlobalData m_global;
GPUScanlineLocalData m_local;
GSCodeGeneratorFunctionMap<GPUSetupPrimCodeGenerator, uint32, SetupPrimPtr> m_sp_map;
GSCodeGeneratorFunctionMap<GPUDrawScanlineCodeGenerator, uint32, DrawScanlinePtr> m_ds_map;
public:
GPUDrawScanline();
virtual ~GPUDrawScanline();
// IDrawScanline
void BeginDraw(const GSRasterizerData* data);
void EndDraw(uint64 frame, uint64 ticks, int actual, int total);
#ifndef ENABLE_JIT_RASTERIZER
void SetupPrim(const GSVertexSW* vertex, const uint32* index, const GSVertexSW& dscan);
void DrawScanline(int pixels, int left, int top, const GSVertexSW& scan);
void DrawEdge(int pixels, int left, int top, const GSVertexSW& scan);
void DrawRect(const GSVector4i& r, const GSVertexSW& v);
#endif
void PrintStats() {m_ds_map.PrintStats();}
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,60 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GPUScanlineEnvironment.h"
#include "GSFunctionMap.h"
using namespace Xbyak;
class GPUDrawScanlineCodeGenerator : public GSCodeGenerator
{
void operator = (const GPUDrawScanlineCodeGenerator&);
GPUScanlineSelector m_sel;
GPUScanlineLocalData& m_local;
void Generate();
void Init();
void Step();
void TestMask();
void SampleTexture();
void ColorTFX();
void AlphaBlend();
void Dither();
void WriteFrame();
void ReadTexel(const Xmm& dst, const Xmm& addr);
template<int shift> void modulate16(const Xmm& a, const Operand& f);
template<int shift> void lerp16(const Xmm& a, const Xmm& b, const Operand& f);
void alltrue();
void blend8(const Xmm& a, const Xmm& b);
void blend(const Xmm& a, const Xmm& b, const Xmm& mask);
public:
GPUDrawScanlineCodeGenerator(void* param, uint32 key, void* code, size_t maxsize);
static const GSVector4i m_test[8];
static __aligned(const uint16, 32) m_dither[4][16];
};

View File

@ -0,0 +1,75 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GPU.h"
__aligned(class, 32) GPUDrawingEnvironment
{
public:
GPURegSTATUS STATUS;
GPURegPRIM PRIM;
GPURegDAREA DAREA;
GPURegDHRANGE DHRANGE;
GPURegDVRANGE DVRANGE;
GPURegDRAREA DRAREATL;
GPURegDRAREA DRAREABR;
GPURegDROFF DROFF;
GPURegTWIN TWIN;
GPURegCLUT CLUT;
GPUDrawingEnvironment()
{
Reset();
}
void Reset()
{
memset(this, 0, sizeof(*this));
STATUS.IDLE = 1;
STATUS.COM = 1;
STATUS.WIDTH0 = 1;
DVRANGE.Y1 = 16;
DVRANGE.Y2 = 256;
}
GSVector4i GetDisplayRect()
{
static int s_width[] = {256, 320, 512, 640, 368, 384, 512, 640};
static int s_height[] = {240, 480};
GSVector4i r;
r.left = DAREA.X & ~7; // FIXME
r.top = DAREA.Y;
r.right = r.left + s_width[(STATUS.WIDTH1 << 2) | STATUS.WIDTH0];
r.bottom = r.top + (DVRANGE.Y2 - DVRANGE.Y1) * s_height[STATUS.HEIGHT] / 240;
return r.rintersect(GSVector4i(0, 0, 1024, 512));
}
float GetFPS()
{
return STATUS.ISPAL ? 50.0f : 59.94f;
}
};

View File

@ -0,0 +1,662 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GPULocalMemory.h"
#include "GSdx.h"
const GSVector4i GPULocalMemory::m_xxxa(0x00008000);
const GSVector4i GPULocalMemory::m_xxbx(0x00007c00);
const GSVector4i GPULocalMemory::m_xgxx(0x000003e0);
const GSVector4i GPULocalMemory::m_rxxx(0x0000001f);
#define VM_REAL_SIZE ((1 << (12 + 11)) * sizeof(uint16))
#define VM_ALLOC_SIZE (VM_REAL_SIZE * 2)
#define TEX_ALLOC_SIZE (256 * 256 * (1 + 1 + 4) * 32)
GPULocalMemory::GPULocalMemory()
{
m_scale.x = std::min<int>(std::max<int>(theApp.GetConfig("scale_x", 0), 0), 2);
m_scale.y = std::min<int>(std::max<int>(theApp.GetConfig("scale_y", 0), 0), 2);
//
int size = VM_REAL_SIZE;
m_vm = (uint16*)vmalloc(VM_ALLOC_SIZE, false);
memset(m_vm, 0, size);
//
m_clut.buff = m_vm + size;
m_clut.dirty = true;
//
size = TEX_ALLOC_SIZE;
m_texture.buff[0] = (uint8*)vmalloc(size, false);
m_texture.buff[1] = m_texture.buff[0] + 256 * 256 * 32;
m_texture.buff[2] = m_texture.buff[1] + 256 * 256 * 32;
memset(m_texture.buff[0], 0, size);
memset(m_texture.valid, 0, sizeof(m_texture.valid));
for(int y = 0, offset = 0; y < 2; y++)
{
for(int x = 0; x < 16; x++, offset += 256 * 256)
{
m_texture.page[0][y][x] = &((uint8*)m_texture.buff[0])[offset];
m_texture.page[1][y][x] = &((uint8*)m_texture.buff[1])[offset];
}
}
for(int y = 0, offset = 0; y < 2; y++)
{
for(int x = 0; x < 16; x++, offset += 256 * 256)
{
m_texture.page[2][y][x] = &((uint32*)m_texture.buff[2])[offset];
}
}
}
GPULocalMemory::~GPULocalMemory()
{
vmfree(m_vm, VM_ALLOC_SIZE);
vmfree(m_texture.buff[0], TEX_ALLOC_SIZE);
}
const uint16* GPULocalMemory::GetCLUT(int tp, int cx, int cy)
{
if(m_clut.dirty || m_clut.tp != tp || m_clut.cx != cx || m_clut.cy != cy)
{
uint16* src = GetPixelAddressScaled(cx << 4, cy);
uint16* dst = m_clut.buff;
if(m_scale.x == 0)
{
memcpy(dst, src, (tp == 0 ? 16 : 256) * 2);
}
else if(m_scale.x == 1)
{
if(tp == 0)
{
for(int i = 0; i < 16; i++)
{
dst[i] = src[i * 2];
}
}
else if(tp == 1)
{
for(int i = 0; i < 256; i++)
{
dst[i] = src[i * 2];
}
}
}
else if(m_scale.x == 2)
{
if(tp == 0)
{
for(int i = 0; i < 16; i++)
{
dst[i] = src[i * 4];
}
}
else if(tp == 1)
{
for(int i = 0; i < 256; i++)
{
dst[i] = src[i * 4];
}
}
}
else
{
ASSERT(0);
}
m_clut.tp = tp;
m_clut.cx = cx;
m_clut.cy = cy;
m_clut.dirty = false;
}
return m_clut.buff;
}
const void* GPULocalMemory::GetTexture(int tp, int tx, int ty)
{
if(tp == 3)
{
ASSERT(0);
return NULL;
}
void* buff = m_texture.page[tp][ty][tx];
uint32 flag = 1 << tx;
if((m_texture.valid[tp][ty] & flag) == 0)
{
// int bpp = 0;
switch(tp)
{
case 0:
ReadPage4(tx, ty, (uint8*)buff);
// bpp = 4;
break;
case 1:
ReadPage8(tx, ty, (uint8*)buff);
// bpp = 8;
break;
case 2:
case 3:
ReadPage16(tx, ty, (uint16*)buff);
// bpp = 16;
default:
// FIXME: __assume(0); // vc9 generates bogus code in release mode
break;
}
// TODO: m_state->m_perfmon.Put(GSPerfMon::Unswizzle, 256 * 256 * bpp >> 3);
m_texture.valid[tp][ty] |= flag;
}
return buff;
}
void GPULocalMemory::Invalidate(const GSVector4i& r)
{
if(!m_clut.dirty)
{
if(r.top <= m_clut.cy && m_clut.cy < r.bottom)
{
int left = m_clut.cx << 4;
int right = left + (m_clut.tp == 0 ? 16 : 256);
if(r.left < right && r.right > left)
{
m_clut.dirty = true;
}
}
}
for(int y = 0, ye = min(r.bottom, 512), j = 0; y < ye; y += 256, j++)
{
if(r.top >= y + 256) continue;
for(int x = 0, xe = min(r.right, 1024), i = 0; x < xe; x += 64, i++)
{
uint32 flag = 1 << i;
if(r.left >= x + 256) continue;
m_texture.valid[2][j] &= ~flag;
if(r.left >= x + 128) continue;
m_texture.valid[1][j] &= ~flag;
if(r.left >= x + 64) continue;
m_texture.valid[0][j] &= ~flag;
}
}
}
void GPULocalMemory::FillRect(const GSVector4i& r, uint16 c)
{
Invalidate(r);
uint16* RESTRICT dst = GetPixelAddressScaled(r.left, r.top);
int w = r.width() << m_scale.x;
int h = r.height() << m_scale.y;
int pitch = GetWidth();
for(int j = 0; j < h; j++, dst += pitch)
{
for(int i = 0; i < w; i++)
{
dst[i] = c;
}
}
}
void GPULocalMemory::WriteRect(const GSVector4i& r, const uint16* RESTRICT src)
{
Invalidate(r);
uint16* RESTRICT dst = GetPixelAddressScaled(r.left, r.top);
int w = r.width();
int h = r.height();
int pitch = GetWidth();
if(m_scale.x == 0)
{
for(int j = 0; j < h; j++, src += w)
{
for(int k = 1 << m_scale.y; k >= 1; k--, dst += pitch)
{
memcpy(dst, src, w * 2);
}
}
}
else if(m_scale.x == 1)
{
for(int j = 0; j < h; j++, src += w)
{
for(int k = 1 << m_scale.y; k >= 1; k--, dst += pitch)
{
for(int i = 0; i < w; i++)
{
dst[i * 2 + 0] = src[i];
dst[i * 2 + 1] = src[i];
}
}
}
}
else if(m_scale.x == 2)
{
for(int j = 0; j < h; j++, src += w)
{
for(int k = 1 << m_scale.y; k >= 1; k--, dst += pitch)
{
for(int i = 0; i < w; i++)
{
dst[i * 4 + 0] = src[i];
dst[i * 4 + 1] = src[i];
dst[i * 4 + 2] = src[i];
dst[i * 4 + 3] = src[i];
}
}
}
}
else
{
ASSERT(0);
}
}
void GPULocalMemory::ReadRect(const GSVector4i& r, uint16* RESTRICT dst)
{
uint16* RESTRICT src = GetPixelAddressScaled(r.left, r.top);
int w = r.width();
int h = r.height();
int pitch = GetWidth() << m_scale.y;
if(m_scale.x == 0)
{
for(int j = 0; j < h; j++, src += pitch, dst += w)
{
memcpy(dst, src, w * 2);
}
}
else if(m_scale.x == 1)
{
for(int j = 0; j < h; j++, src += pitch, dst += w)
{
for(int i = 0; i < w; i++)
{
dst[i] = src[i * 2];
}
}
}
else if(m_scale.x == 2)
{
for(int j = 0; j < h; j++, src += pitch, dst += w)
{
for(int i = 0; i < w; i++)
{
dst[i] = src[i * 4];
}
}
}
else
{
ASSERT(0);
}
}
void GPULocalMemory::MoveRect(int sx, int sy, int dx, int dy, int w, int h)
{
Invalidate(GSVector4i(dx, dy, dx + w, dy + h));
uint16* s = GetPixelAddressScaled(sx, sy);
uint16* d = GetPixelAddressScaled(dx, dy);
w <<= m_scale.x;
h <<= m_scale.y;
int pitch = GetWidth();
for(int i = 0; i < h; i++, s += pitch, d += pitch)
{
memcpy(d, s, w * sizeof(uint16));
}
}
void GPULocalMemory::ReadPage4(int tx, int ty, uint8* RESTRICT dst)
{
uint16* src = GetPixelAddressScaled(tx << 6, ty << 8);
int pitch = GetWidth() << m_scale.y;
if(m_scale.x == 0)
{
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
{
for(int i = 0; i < 64; i++)
{
dst[i * 4 + 0] = (src[i] >> 0) & 0xf;
dst[i * 4 + 1] = (src[i] >> 4) & 0xf;
dst[i * 4 + 2] = (src[i] >> 8) & 0xf;
dst[i * 4 + 3] = (src[i] >> 12) & 0xf;
}
}
}
else if(m_scale.x == 1)
{
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
{
for(int i = 0; i < 64; i++)
{
dst[i * 4 + 0] = (src[i * 2] >> 0) & 0xf;
dst[i * 4 + 1] = (src[i * 2] >> 4) & 0xf;
dst[i * 4 + 2] = (src[i * 2] >> 8) & 0xf;
dst[i * 4 + 3] = (src[i * 2] >> 12) & 0xf;
}
}
}
else if(m_scale.x == 2)
{
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
{
for(int i = 0; i < 64; i++)
{
dst[i * 4 + 0] = (src[i * 4] >> 0) & 0xf;
dst[i * 4 + 1] = (src[i * 4] >> 4) & 0xf;
dst[i * 4 + 2] = (src[i * 4] >> 8) & 0xf;
dst[i * 4 + 3] = (src[i * 4] >> 12) & 0xf;
}
}
}
else
{
ASSERT(0);
}
}
void GPULocalMemory::ReadPage8(int tx, int ty, uint8* RESTRICT dst)
{
uint16* src = GetPixelAddressScaled(tx << 6, ty << 8);
int pitch = GetWidth() << m_scale.y;
if(m_scale.x == 0)
{
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
{
memcpy(dst, src, 256);
}
}
else if(m_scale.x == 1)
{
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
{
for(int i = 0; i < 128; i++)
{
((uint16*)dst)[i] = src[i * 2];
}
}
}
else if(m_scale.x == 2)
{
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
{
for(int i = 0; i < 128; i++)
{
((uint16*)dst)[i] = src[i * 4];
}
}
}
else
{
ASSERT(0);
}
}
void GPULocalMemory::ReadPage16(int tx, int ty, uint16* RESTRICT dst)
{
uint16* src = GetPixelAddressScaled(tx << 6, ty << 8);
int pitch = GetWidth() << m_scale.y;
if(m_scale.x == 0)
{
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
{
memcpy(dst, src, 512);
}
}
else if(m_scale.x == 1)
{
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
{
for(int i = 0; i < 256; i++)
{
dst[i] = src[i * 2];
}
}
}
else if(m_scale.x == 2)
{
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
{
for(int i = 0; i < 256; i++)
{
dst[i] = src[i * 4];
}
}
}
else
{
ASSERT(0);
}
}
void GPULocalMemory::ReadFrame32(const GSVector4i& r, uint32* RESTRICT dst, bool rgb24)
{
uint16* src = GetPixelAddress(r.left, r.top);
int pitch = GetWidth();
if(rgb24)
{
for(int i = r.top; i < r.bottom; i++, src += pitch, dst += pitch)
{
Expand24(src, dst, r.width());
}
}
else
{
for(int i = r.top; i < r.bottom; i++, src += pitch, dst += pitch)
{
Expand16(src, dst, r.width());
}
}
}
void GPULocalMemory::Expand16(const uint16* RESTRICT src, uint32* RESTRICT dst, int pixels)
{
GSVector4i rm = m_rxxx;
GSVector4i gm = m_xgxx;
GSVector4i bm = m_xxbx;
GSVector4i am = m_xxxa;
GSVector4i* s = (GSVector4i*)src;
GSVector4i* d = (GSVector4i*)dst;
for(int i = 0, j = pixels >> 3; i < j; i++)
{
GSVector4i c = s[i];
GSVector4i l = c.upl16();
GSVector4i h = c.uph16();
d[i * 2 + 0] = ((l & rm) << 3) | ((l & gm) << 6) | ((l & bm) << 9) | ((l & am) << 16);
d[i * 2 + 1] = ((h & rm) << 3) | ((h & gm) << 6) | ((h & bm) << 9) | ((h & am) << 16);
}
}
void GPULocalMemory::Expand24(const uint16* RESTRICT src, uint32* RESTRICT dst, int pixels)
{
uint8* s = (uint8*)src;
if(m_scale.x == 0)
{
for(int i = 0; i < pixels; i += 2, s += 6)
{
dst[i + 0] = (s[2] << 16) | (s[1] << 8) | s[0];
dst[i + 1] = (s[5] << 16) | (s[4] << 8) | s[3];
}
}
else if(m_scale.x == 1)
{
for(int i = 0; i < pixels; i += 4, s += 12)
{
dst[i + 0] = dst[i + 1] = (s[4] << 16) | (s[1] << 8) | s[0];
dst[i + 2] = dst[i + 3] = (s[9] << 16) | (s[8] << 8) | s[5];
}
}
else if(m_scale.x == 2)
{
for(int i = 0; i < pixels; i += 8, s += 24)
{
dst[i + 0] = dst[i + 1] = dst[i + 2] = dst[i + 3] = (s[8] << 16) | (s[1] << 8) | s[0];
dst[i + 4] = dst[i + 5] = dst[i + 6] = dst[i + 7] = (s[17] << 16) | (s[16] << 8) | s[9];
}
}
else
{
ASSERT(0);
}
}
#include "GSTextureSW.h"
void GPULocalMemory::SaveBMP(const string& fn, const GSVector4i& r2, int tp, int cx, int cy)
{
GSVector4i r;
r.left = r2.left << m_scale.x;
r.top = r2.top << m_scale.y;
r.right = r2.right << m_scale.x;
r.bottom = r2.bottom << m_scale.y;
r.left &= ~1;
r.right &= ~1;
GSTextureSW t(GSTexture::Offscreen, r.width(), r.height());
GSTexture::GSMap m;
if(t.Map(m, NULL))
{
int pitch = GetWidth();
const uint16* RESTRICT src = GetPixelAddress(r.left, r.top);
const uint16* RESTRICT clut = GetCLUT(tp, cx, cy);
uint8* RESTRICT dst = m.bits;
uint16* RESTRICT buff = (uint16*)_aligned_malloc(pitch * sizeof(uint16), 32);
uint32* RESTRICT buff32 = (uint32*)_aligned_malloc(pitch * sizeof(uint32), 32);
for(int j = r.top; j < r.bottom; j++, src += pitch, dst += m.pitch)
{
switch(tp)
{
case 0: // 4 bpp
for(int i = 0, k = r.width() / 2; i < k; i++)
{
buff[i * 2 + 0] = clut[((uint8*)src)[i] & 0xf];
buff[i * 2 + 1] = clut[((uint8*)src)[i] >> 4];
}
break;
case 1: // 8 bpp
for(int i = 0, k = r.width(); i < k; i++)
{
buff[i] = clut[((uint8*)src)[i]];
}
break;
case 2: // 16 bpp;
for(int i = 0, k = r.width(); i < k; i++)
{
buff[i] = src[i];
}
break;
case 3: // 24 bpp
// TODO
break;
}
Expand16(buff, buff32, r.width());
for(int i = 0, k = r.width(); i < k; i++)
{
buff32[i] = (buff32[i] & 0xff00ff00) | ((buff32[i] & 0x00ff0000) >> 16) | ((buff32[i] & 0x000000ff) << 16);
}
memcpy(dst, buff32, r.width() << 2);
}
_aligned_free(buff);
_aligned_free(buff32);
t.Unmap();
t.Save(fn);
}
}

View File

@ -0,0 +1,84 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GPU.h"
#include "GSVector.h"
class GPULocalMemory
{
static const GSVector4i m_xxxa;
static const GSVector4i m_xxbx;
static const GSVector4i m_xgxx;
static const GSVector4i m_rxxx;
uint16* m_vm;
struct
{
uint16* buff;
int tp, cx, cy;
bool dirty;
} m_clut;
struct
{
uint8* buff[3];
void* page[3][2][16];
uint16 valid[3][2];
} m_texture;
GSVector2i m_scale;
public:
GPULocalMemory();
virtual ~GPULocalMemory();
GSVector2i GetScale() {return m_scale;}
int GetWidth() {return 1 << (10 + m_scale.x);}
int GetHeight() {return 1 << (9 + m_scale.y);}
uint16* GetPixelAddress(int x, int y) const {return &m_vm[(y << (10 + m_scale.x)) + x];}
uint16* GetPixelAddressScaled(int x, int y) const {return &m_vm[((y << m_scale.y) << (10 + m_scale.x)) + (x << m_scale.x)];}
const uint16* GetCLUT(int tp, int cx, int cy);
const void* GetTexture(int tp, int tx, int ty);
void Invalidate(const GSVector4i& r);
void FillRect(const GSVector4i& r, uint16 c);
void WriteRect(const GSVector4i& r, const uint16* RESTRICT src);
void ReadRect(const GSVector4i& r, uint16* RESTRICT dst);
void MoveRect(int sx, int sy, int dx, int dy, int w, int h);
void ReadPage4(int tx, int ty, uint8* RESTRICT dst);
void ReadPage8(int tx, int ty, uint8* RESTRICT dst);
void ReadPage16(int tx, int ty, uint16* RESTRICT dst);
void ReadFrame32(const GSVector4i& r, uint32* RESTRICT dst, bool rgb24);
void Expand16(const uint16* RESTRICT src, uint32* RESTRICT dst, int pixels);
void Expand24(const uint16* RESTRICT src, uint32* RESTRICT dst, int pixels);
void SaveBMP(const string& fn, const GSVector4i& r, int tp, int cx, int cy);
};

View File

@ -0,0 +1,270 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GPURenderer.h"
#include "GSdx.h"
#ifdef _WIN32
map<HWND, GPURenderer*> GPURenderer::m_wnd2gpu;
#endif
GPURenderer::GPURenderer(GSDevice* dev)
: m_dev(dev)
{
m_filter = theApp.GetConfig("filter", 0);
m_dither = theApp.GetConfig("dithering", 1);
m_aspectratio = theApp.GetConfig("AspectRatio", 1);
m_vsync = !!theApp.GetConfig("vsync", 0);
m_fxaa = !!theApp.GetConfig("fxaa", 0);
m_shaderfx = !!theApp.GetConfig("shaderfx", 0);
m_scale = m_mem.GetScale();
m_shadeboost = !!theApp.GetConfig("ShadeBoost", 0);
#ifdef _WIN32
m_hWnd = NULL;
m_wndproc = NULL;
m_wnd = new GSWndDX();
#endif
}
GPURenderer::~GPURenderer()
{
#ifdef _WIN32
if(m_wndproc)
{
SetWindowLongPtr(m_hWnd, GWLP_WNDPROC, (LONG_PTR)m_wndproc);
m_wnd2gpu.erase(m_hWnd);
}
#endif
}
bool GPURenderer::Create(void* hWnd)
{
#ifdef _WIN32
// TODO: move subclassing inside GSWnd::Attach
m_hWnd = (HWND)hWnd;
m_wndproc = (WNDPROC)GetWindowLongPtr(m_hWnd, GWLP_WNDPROC);
SetWindowLongPtr(m_hWnd, GWLP_WNDPROC, (LONG_PTR)WndProc);
if(!m_wnd->Attach(m_hWnd))
{
return false;
}
m_wnd2gpu[m_hWnd] = this;
SetWindowLong(m_hWnd, GWL_STYLE, GetWindowLong(m_hWnd, GWL_STYLE) | WS_OVERLAPPEDWINDOW);
#endif
m_wnd->Show();
if(!m_dev->Create(m_wnd))
{
return false;
}
m_dev->SetVSync(m_vsync);
Reset();
return true;
}
bool GPURenderer::Merge()
{
GSTexture* st[2] = {GetOutput(), NULL};
if(!st[0])
{
return false;
}
GSVector2i s = st[0]->GetSize();
GSVector4 sr[2];
GSVector4 dr[2];
sr[0] = GSVector4(0, 0, 1, 1);
dr[0] = GSVector4(0, 0, s.x, s.y);
m_dev->Merge(st, sr, dr, s, 1, 1, GSVector4(0, 0, 0, 1));
if(m_shadeboost)
{
m_dev->ShadeBoost();
}
if (m_shaderfx)
{
m_dev->ExternalFX();
}
if(m_fxaa)
{
m_dev->FXAA();
}
return true;
}
void GPURenderer::VSync()
{
GSPerfMonAutoTimer pmat(&m_perfmon);
m_perfmon.Put(GSPerfMon::Frame);
// m_env.STATUS.LCF = ~m_env.STATUS.LCF; // ?
#ifdef _WIN32
if(!IsWindow(m_hWnd)) return;
#endif
Flush();
if(!m_dev->IsLost(true))
{
if(!Merge())
{
return;
}
}
else
{
ResetDevice();
}
// osd
if((m_perfmon.GetFrame() & 0x1f) == 0)
{
m_perfmon.Update();
double fps = 1000.0f / m_perfmon.Get(GSPerfMon::Frame);
GSVector4i r = m_env.GetDisplayRect();
int w = r.width() << m_scale.x;
int h = r.height() << m_scale.y;
string s = format(
"%lld | %d x %d | %.2f fps (%d%%) | %d/%d | %d%% CPU | %.2f | %.2f",
m_perfmon.GetFrame(), w, h, fps, (int)(100.0 * fps / m_env.GetFPS()),
(int)m_perfmon.Get(GSPerfMon::Prim),
(int)m_perfmon.Get(GSPerfMon::Draw),
m_perfmon.CPU(),
m_perfmon.Get(GSPerfMon::Swizzle) / 1024,
m_perfmon.Get(GSPerfMon::Unswizzle) / 1024
);
double fillrate = m_perfmon.Get(GSPerfMon::Fillrate);
if(fillrate > 0)
{
s = format("%s | %.2f mpps", s.c_str(), fps * fillrate / (1024 * 1024));
}
m_wnd->SetWindowText(s.c_str());
}
GSVector4i r = m_wnd->GetClientRect();
m_dev->Present(r.fit(m_aspectratio), 0);
}
bool GPURenderer::MakeSnapshot(const string& path)
{
time_t t = time(NULL);
char buff[16];
if(!strftime(buff, sizeof(buff), "%Y%m%d%H%M%S", localtime(&t)))
{
return false;
}
if(GSTexture* t = m_dev->GetCurrent())
{
return t->Save(format("%s_%s.bmp", path.c_str(), buff));
}
return false;
}
#ifdef _WIN32
LRESULT CALLBACK GPURenderer::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
map<HWND, GPURenderer*>::iterator i = m_wnd2gpu.find(hWnd);
if(i != m_wnd2gpu.end())
{
return i->second->OnMessage(message, wParam, lParam);
}
ASSERT(0);
return 0;
}
LRESULT GPURenderer::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
{
if(message == WM_KEYUP)
{
switch(wParam)
{
case VK_DELETE:
m_filter = (m_filter + 1) % 3;
return 0;
case VK_END:
m_dither = m_dither ? 0 : 1;
return 0;
case VK_NEXT:
m_aspectratio = (m_aspectratio + 1) % 3;
return 0;
case VK_PRIOR:
m_fxaa = !m_fxaa;
return 0;
case VK_HOME:
m_shaderfx = !m_shaderfx;
return 0;
}
}
return CallWindowProc(m_wndproc, m_hWnd, message, wParam, lParam);
}
#endif

View File

@ -0,0 +1,202 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GPUState.h"
#include "GSVertexList.h"
#include "GSDevice.h"
#ifdef _WIN32
#include "GSWndDX.h"
#endif
class GPURenderer : public GPUState
{
bool Merge();
protected:
GSDevice* m_dev;
int m_filter;
int m_dither;
int m_aspectratio;
bool m_vsync;
bool m_shaderfx;
bool m_fxaa;
bool m_shadeboost;
GSVector2i m_scale;
virtual void ResetDevice() {}
virtual GSTexture* GetOutput() = 0;
#ifdef _WIN32
HWND m_hWnd;
WNDPROC m_wndproc;
static map<HWND, GPURenderer*> m_wnd2gpu;
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
#endif
GSWnd* m_wnd;
public:
GPURenderer(GSDevice* dev);
virtual ~GPURenderer();
virtual bool Create(void* hWnd);
virtual void VSync();
virtual bool MakeSnapshot(const string& path);
};
template<class Vertex>
class GPURendererT : public GPURenderer
{
protected:
Vertex* m_vertices;
int m_count;
int m_maxcount;
GSVertexList<Vertex> m_vl;
void Reset()
{
m_count = 0;
m_vl.RemoveAll();
GPURenderer::Reset();
}
void ResetPrim()
{
m_vl.RemoveAll();
}
void FlushPrim()
{
if(m_count > 0)
{
/*
Dump("db");
if(m_env.PRIM.TME)
{
GSVector4i r;
r.left = m_env.STATUS.TX << 6;
r.top = m_env.STATUS.TY << 8;
r.right = r.left + 256;
r.bottom = r.top + 256;
Dump(format("da_%d_%d_%d_%d_%d", m_env.STATUS.TP, r.left, r.top, r.right, r.bottom).c_str(), m_env.STATUS.TP, r, false);
}
*/
Draw();
m_count = 0;
//Dump("dc", false);
}
}
void GrowVertexBuffer()
{
int maxcount = std::max<int>(m_maxcount * 3 / 2, 10000);
Vertex* vertices = (Vertex*)_aligned_malloc(sizeof(Vertex) * maxcount, 32);
if(vertices == NULL)
{
printf("GSdx: failed to allocate %d bytes for verticles.\n", (int)sizeof(Vertex) * maxcount);
throw GSDXError();
}
if(m_vertices != NULL)
{
memcpy(vertices, m_vertices, sizeof(Vertex) * m_maxcount);
_aligned_free(m_vertices);
}
m_vertices = vertices;
m_maxcount = maxcount - 100;
}
__forceinline Vertex* DrawingKick(int& count)
{
count = (int)m_env.PRIM.VTX;
if(m_vl.GetCount() < count)
{
return NULL;
}
if(m_count >= m_maxcount)
{
GrowVertexBuffer();
}
Vertex* v = &m_vertices[m_count];
switch(m_env.PRIM.TYPE)
{
case GPU_POLYGON:
m_vl.GetAt(0, v[0]);
m_vl.GetAt(1, v[1]);
m_vl.GetAt(2, v[2]);
m_vl.RemoveAll();
break;
case GPU_LINE:
m_vl.GetAt(0, v[0]);
m_vl.GetAt(1, v[1]);
m_vl.RemoveAll();
break;
case GPU_SPRITE:
m_vl.GetAt(0, v[0]);
m_vl.GetAt(1, v[1]);
m_vl.RemoveAll();
break;
default:
ASSERT(0);
m_vl.RemoveAll();
return NULL;
}
return v;
}
virtual void VertexKick() = 0;
virtual void Draw() = 0;
public:
GPURendererT(GSDevice* dev)
: GPURenderer(dev)
, m_vertices(NULL)
, m_count(0)
, m_maxcount(0)
{
}
virtual ~GPURendererT()
{
if(m_vertices) _aligned_free(m_vertices);
}
};

View File

@ -0,0 +1,205 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GPURendererSW.h"
//#include "GSdx.h"
GPURendererSW::GPURendererSW(GSDevice* dev, int threads)
: GPURendererT<GSVertexSW>(dev)
, m_texture(NULL)
{
m_output = (uint32*)_aligned_malloc(m_mem.GetWidth() * m_mem.GetHeight() * sizeof(uint32), 32);
m_rl = GSRasterizerList::Create<GPUDrawScanline>(threads, &m_perfmon);
}
GPURendererSW::~GPURendererSW()
{
delete m_texture;
delete m_rl;
_aligned_free(m_output);
}
void GPURendererSW::ResetDevice()
{
delete m_texture;
m_texture = NULL;
}
GSTexture* GPURendererSW::GetOutput()
{
GSVector4i r = m_env.GetDisplayRect();
r.left <<= m_scale.x;
r.top <<= m_scale.y;
r.right <<= m_scale.x;
r.bottom <<= m_scale.y;
if(m_dev->ResizeTexture(&m_texture, r.width(), r.height()))
{
m_mem.ReadFrame32(r, m_output, !!m_env.STATUS.ISRGB24);
m_texture->Update(r.rsize(), m_output, m_mem.GetWidth() * sizeof(uint32));
}
return m_texture;
}
void GPURendererSW::Draw()
{
GPUDrawScanline::SharedData* sd = new GPUDrawScanline::SharedData();
shared_ptr<GSRasterizerData> data(sd);
GPUScanlineGlobalData& gd = sd->global;
const GPUDrawingEnvironment& env = m_env;
gd.sel.key = 0;
gd.sel.iip = env.PRIM.IIP;
gd.sel.me = env.STATUS.ME;
if(env.PRIM.ABE)
{
gd.sel.abe = env.PRIM.ABE;
gd.sel.abr = env.STATUS.ABR;
}
gd.sel.tge = env.PRIM.TGE;
if(env.PRIM.TME)
{
gd.sel.tme = env.PRIM.TME;
gd.sel.tlu = env.STATUS.TP < 2;
gd.sel.twin = (env.TWIN.u32 & 0xfffff) != 0;
gd.sel.ltf = m_filter == 1 && env.PRIM.TYPE == GPU_POLYGON || m_filter == 2 ? 1 : 0;
const void* t = m_mem.GetTexture(env.STATUS.TP, env.STATUS.TX, env.STATUS.TY);
if(!t) {ASSERT(0); return;}
gd.tex = t;
gd.clut = (uint16*)_aligned_malloc(sizeof(uint16) * 256, 32);
memcpy(gd.clut, m_mem.GetCLUT(env.STATUS.TP, env.CLUT.X, env.CLUT.Y), sizeof(uint16) * (env.STATUS.TP == 0 ? 16 : 256));
gd.twin = GSVector4i(env.TWIN.TWW, env.TWIN.TWH, env.TWIN.TWX, env.TWIN.TWY);
}
gd.sel.dtd = m_dither ? env.STATUS.DTD : 0;
gd.sel.md = env.STATUS.MD;
gd.sel.sprite = env.PRIM.TYPE == GPU_SPRITE;
gd.sel.scalex = m_mem.GetScale().x;
gd.vm = m_mem.GetPixelAddress(0, 0);
data->scissor.left = (int)m_env.DRAREATL.X << m_scale.x;
data->scissor.top = (int)m_env.DRAREATL.Y << m_scale.y;
data->scissor.right = min((int)(m_env.DRAREABR.X + 1) << m_scale.x, m_mem.GetWidth());
data->scissor.bottom = min((int)(m_env.DRAREABR.Y + 1) << m_scale.y, m_mem.GetHeight());
data->buff = (uint8*)_aligned_malloc(sizeof(GSVertexSW) * m_count, 32);
data->vertex = (GSVertexSW*)data->buff;
data->vertex_count = m_count;
memcpy(data->vertex, m_vertices, sizeof(GSVertexSW) * m_count);
data->frame = m_perfmon.GetFrame();
int prims = 0;
switch(env.PRIM.TYPE)
{
case GPU_POLYGON: data->primclass = GS_TRIANGLE_CLASS; prims = data->vertex_count / 3; break;
case GPU_LINE: data->primclass = GS_LINE_CLASS; prims = data->vertex_count / 2; break;
case GPU_SPRITE: data->primclass = GS_SPRITE_CLASS; prims = data->vertex_count / 2; break;
default: __assume(0);
}
// TODO: VertexTrace
GSVector4 tl(+1e10f);
GSVector4 br(-1e10f);
GSVertexSW* v = data->vertex;
for(int i = 0, j = data->vertex_count; i < j; i++)
{
GSVector4 p = v[i].p;
tl = tl.min(p);
br = br.max(p);
}
data->bbox = GSVector4i(tl.xyxy(br));
GSVector4i r = data->bbox.rintersect(data->scissor);
r.left >>= m_scale.x;
r.top >>= m_scale.y;
r.right >>= m_scale.x;
r.bottom >>= m_scale.y;
Invalidate(r);
m_rl->Queue(data);
m_rl->Sync();
m_perfmon.Put(GSPerfMon::Draw, 1);
m_perfmon.Put(GSPerfMon::Prim, prims);
m_perfmon.Put(GSPerfMon::Fillrate, m_rl->GetPixels());
}
void GPURendererSW::VertexKick()
{
GSVertexSW& dst = m_vl.AddTail();
// TODO: x/y + off.x/y should wrap around at +/-1024
int x = (int)(m_v.XY.X + m_env.DROFF.X) << m_scale.x;
int y = (int)(m_v.XY.Y + m_env.DROFF.Y) << m_scale.y;
int u = m_v.UV.X;
int v = m_v.UV.Y;
GSVector4 pt(x, y, u, v);
dst.p = pt.xyxy(GSVector4::zero());
dst.t = (pt.zwzw(GSVector4::zero()) + GSVector4(0.125f)) * 256.0f;
// dst.c = GSVector4(m_v.RGB.u32) * 128.0f;
dst.c = GSVector4(GSVector4i::load((int)m_v.RGB.u32).u8to32() << 7);
int count = 0;
if(DrawingKick(count))
{
// TODO
m_count += count;
}
}

View File

@ -0,0 +1,42 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GPURenderer.h"
#include "GPUDrawScanline.h"
class GPURendererSW : public GPURendererT<GSVertexSW>
{
protected:
IRasterizer* m_rl;
GSTexture* m_texture;
uint32* m_output;
void ResetDevice();
GSTexture* GetOutput();
void VertexKick();
void Draw();
public:
GPURendererSW(GSDevice* dev, int threads);
virtual ~GPURendererSW();
};

View File

@ -0,0 +1,78 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSVector.h"
#include "GPULocalMemory.h"
union GPUScanlineSelector
{
struct
{
uint32 iip:1; // 0
uint32 me:1; // 1
uint32 abe:1; // 2
uint32 abr:2; // 3
uint32 tge:1; // 5
uint32 tme:1; // 6
uint32 twin:1; // 7
uint32 tlu:1; // 8
uint32 dtd:1; // 9
uint32 ltf:1; // 10
uint32 md:1; // 11
uint32 sprite:1; // 12
uint32 scalex:2; // 13
};
struct
{
uint32 _pad1:1; // 0
uint32 rfb:2; // 1
uint32 _pad2:2; // 3
uint32 tfx:2; // 5
};
uint32 key;
operator uint32() const {return key;}
};
__aligned(struct, 32) GPUScanlineGlobalData
{
GPUScanlineSelector sel;
void* vm;
const void* tex;
uint16* clut;
GSVector4i twin; // TWW, TWH, TWX, TWY
};
__aligned(struct, 32) GPUScanlineLocalData
{
const GPUScanlineGlobalData* gd;
struct {GSVector4i u, v;} twin[3];
struct {GSVector4i s, t, r, g, b, _pad[3];} d;
struct {GSVector4i st, c;} d8;
struct {GSVector4i s, t, r, b, g, uf, vf, dither, fd, test;} temp;
};

View File

@ -0,0 +1,151 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSdx.h"
#include "GSUtil.h"
#include "GPUSettingsDlg.h"
#include "resource.h"
GPUSettingsDlg::GPUSettingsDlg()
: GSDialog(IDD_GPUCONFIG)
{
}
void GPUSettingsDlg::OnInit()
{
__super::OnInit();
m_modes.clear();
{
D3DDISPLAYMODE mode;
memset(&mode, 0, sizeof(mode));
m_modes.push_back(mode);
ComboBoxAppend(IDC_RESOLUTION, "Please select...", (LPARAM)&m_modes.back(), true);
if(CComPtr<IDirect3D9> d3d = Direct3DCreate9(D3D_SDK_VERSION))
{
uint32 w = theApp.GetConfig("ModeWidth", 0);
uint32 h = theApp.GetConfig("ModeHeight", 0);
uint32 hz = theApp.GetConfig("ModeRefreshRate", 0);
uint32 n = d3d->GetAdapterModeCount(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8);
for(uint32 i = 0; i < n; i++)
{
if(S_OK == d3d->EnumAdapterModes(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8, i, &mode))
{
m_modes.push_back(mode);
string str = format("%dx%d %dHz", mode.Width, mode.Height, mode.RefreshRate);
ComboBoxAppend(IDC_RESOLUTION, str.c_str(), (LPARAM)&m_modes.back(), w == mode.Width && h == mode.Height && hz == mode.RefreshRate);
}
}
}
}
ComboBoxInit(IDC_RENDERER, theApp.m_gpu_renderers, theApp.GetConfig("Renderer", 0));
ComboBoxInit(IDC_FILTER, theApp.m_gpu_filter, theApp.GetConfig("filter", 0));
ComboBoxInit(IDC_DITHERING, theApp.m_gpu_dithering, theApp.GetConfig("dithering", 1));
ComboBoxInit(IDC_ASPECTRATIO, theApp.m_gpu_aspectratio, theApp.GetConfig("AspectRatio", 1));
ComboBoxInit(IDC_SCALE, theApp.m_gpu_scale, theApp.GetConfig("scale_x", 0) | (theApp.GetConfig("scale_y", 0) << 2));
CheckDlgButton(m_hWnd, IDC_WINDOWED, theApp.GetConfig("windowed", 1));
SendMessage(GetDlgItem(m_hWnd, IDC_SWTHREADS), UDM_SETRANGE, 0, MAKELPARAM(16, 0));
SendMessage(GetDlgItem(m_hWnd, IDC_SWTHREADS), UDM_SETPOS, 0, MAKELPARAM(theApp.GetConfig("extrathreads", DEFAULT_EXTRA_RENDERING_THREADS), 0));
UpdateControls();
}
bool GPUSettingsDlg::OnCommand(HWND hWnd, UINT id, UINT code)
{
if(id == IDC_RENDERER && code == CBN_SELCHANGE)
{
UpdateControls();
}
else if(id == IDOK)
{
INT_PTR data;
if(ComboBoxGetSelData(IDC_RESOLUTION, data))
{
const D3DDISPLAYMODE* mode = (D3DDISPLAYMODE*)data;
theApp.SetConfig("ModeWidth", (int)mode->Width);
theApp.SetConfig("ModeHeight", (int)mode->Height);
theApp.SetConfig("ModeRefreshRate", (int)mode->RefreshRate);
}
if(ComboBoxGetSelData(IDC_RENDERER, data))
{
theApp.SetConfig("Renderer", (int)data);
}
if(ComboBoxGetSelData(IDC_FILTER, data))
{
theApp.SetConfig("filter", (int)data);
}
if(ComboBoxGetSelData(IDC_DITHERING, data))
{
theApp.SetConfig("dithering", (int)data);
}
if(ComboBoxGetSelData(IDC_ASPECTRATIO, data))
{
theApp.SetConfig("AspectRatio", (int)data);
}
if(ComboBoxGetSelData(IDC_SCALE, data))
{
theApp.SetConfig("scale_x", data & 3);
theApp.SetConfig("scale_y", (data >> 2) & 3);
}
theApp.SetConfig("extrathreads", (int)SendMessage(GetDlgItem(m_hWnd, IDC_SWTHREADS), UDM_GETPOS, 0, 0));
theApp.SetConfig("windowed", (int)IsDlgButtonChecked(m_hWnd, IDC_WINDOWED));
}
return __super::OnCommand(hWnd, id, code);
}
void GPUSettingsDlg::UpdateControls()
{
INT_PTR i;
if(ComboBoxGetSelData(IDC_RENDERER, i))
{
bool dx9 = i == 0;
bool dx11 = i == 1;
bool sw = i >= 0 && i <= 2;
ShowWindow(GetDlgItem(m_hWnd, IDC_LOGO9), dx9 ? SW_SHOW : SW_HIDE);
ShowWindow(GetDlgItem(m_hWnd, IDC_LOGO11), dx11 ? SW_SHOW : SW_HIDE);
EnableWindow(GetDlgItem(m_hWnd, IDC_SCALE), sw);
EnableWindow(GetDlgItem(m_hWnd, IDC_SWTHREADS_EDIT), sw);
EnableWindow(GetDlgItem(m_hWnd, IDC_SWTHREADS), sw);
}
}

View File

@ -0,0 +1,39 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSDialog.h"
#include "GSSetting.h"
class GPUSettingsDlg : public GSDialog
{
list<D3DDISPLAYMODE> m_modes;
void UpdateControls();
protected:
void OnInit();
bool OnCommand(HWND hWnd, UINT id, UINT code);
public:
GPUSettingsDlg();
};

View File

@ -0,0 +1,228 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
// TODO: x64
#include "stdafx.h"
#include "GPUSetupPrimCodeGenerator.h"
#include "GSVertexSW.h"
using namespace Xbyak;
static const int _args = 0;
static const int _vertex = _args + 4;
static const int _index = _args + 8;
static const int _dscan = _args + 12;
GPUSetupPrimCodeGenerator::GPUSetupPrimCodeGenerator(void* param, uint32 key, void* code, size_t maxsize)
: GSCodeGenerator(code, maxsize)
, m_local(*(GPUScanlineLocalData*)param)
{
m_sel.key = key;
Generate();
}
void GPUSetupPrimCodeGenerator::Generate()
{
if(m_sel.tme && !m_sel.twin)
{
pcmpeqd(xmm0, xmm0);
if(m_sel.sprite)
{
// t = (GSVector4i(vertices[1].t) >> 8) - GSVector4i::x00000001();
mov(ecx, ptr[esp + _index]);
mov(ecx, ptr[ecx + sizeof(uint32) * 1]);
shl(ecx, 6); // * sizeof(GSVertexSW)
add(ecx, ptr[esp + _vertex]);
cvttps2dq(xmm1, ptr[ecx + offsetof(GSVertexSW, t)]);
psrld(xmm1, 8);
psrld(xmm0, 31);
psubd(xmm1, xmm0);
// t = t.ps32(t);
// t = t.upl16(t);
packssdw(xmm1, xmm1);
punpcklwd(xmm1, xmm1);
// m_local.twin[2].u = t.xxxx();
// m_local.twin[2].v = t.yyyy();
pshufd(xmm2, xmm1, _MM_SHUFFLE(0, 0, 0, 0));
pshufd(xmm3, xmm1, _MM_SHUFFLE(1, 1, 1, 1));
movdqa(ptr[&m_local.twin[2].u], xmm2);
movdqa(ptr[&m_local.twin[2].v], xmm3);
}
else
{
// TODO: not really needed
// m_local.twin[2].u = GSVector4i::x00ff();
// m_local.twin[2].v = GSVector4i::x00ff();
psrlw(xmm0, 8);
movdqa(ptr[&m_local.twin[2].u], xmm0);
movdqa(ptr[&m_local.twin[2].v], xmm0);
}
}
if(m_sel.tme || m_sel.iip && m_sel.tfx != 3)
{
mov(edx, dword[esp + _dscan]);
for(int i = 0; i < 3; i++)
{
movaps(Xmm(5 + i), ptr[&m_shift[i]]);
}
// GSVector4 dt = dscan.t;
// GSVector4 dc = dscan.c;
movaps(xmm4, ptr[edx + offsetof(GSVertexSW, c)]);
movaps(xmm3, ptr[edx + offsetof(GSVertexSW, t)]);
// GSVector4i dtc8 = GSVector4i(dt * 8.0f).ps32(GSVector4i(dc * 8.0f));
movaps(xmm1, xmm3);
mulps(xmm1, xmm5);
cvttps2dq(xmm1, xmm1);
movaps(xmm2, xmm4);
mulps(xmm2, xmm5);
cvttps2dq(xmm2, xmm2);
packssdw(xmm1, xmm2);
if(m_sel.tme)
{
// m_local.d8.st = dtc8.upl16(dtc8);
movdqa(xmm0, xmm1);
punpcklwd(xmm0, xmm0);
movdqa(ptr[&m_local.d8.st], xmm0);
}
if(m_sel.iip && m_sel.tfx != 3)
{
// m_local.d8.c = dtc8.uph16(dtc8);
punpckhwd(xmm1, xmm1);
movdqa(ptr[&m_local.d8.c], xmm1);
}
// xmm3 = dt
// xmm4 = dc
// xmm6 = ps0123
// xmm7 = ps4567
// xmm0, xmm1, xmm2, xmm5 = free
if(m_sel.tme)
{
// GSVector4 dtx = dt.xxxx();
// GSVector4 dty = dt.yyyy();
movaps(xmm0, xmm3);
shufps(xmm3, xmm3, _MM_SHUFFLE(0, 0, 0, 0));
shufps(xmm0, xmm0, _MM_SHUFFLE(1, 1, 1, 1));
// m_local.d.s = GSVector4i(dtx * ps0123).ps32(GSVector4i(dtx * ps4567));
movaps(xmm1, xmm3);
mulps(xmm3, xmm6);
mulps(xmm1, xmm7);
cvttps2dq(xmm3, xmm3);
cvttps2dq(xmm1, xmm1);
packssdw(xmm3, xmm1);
movdqa(ptr[&m_local.d.s], xmm3);
// m_local.d.t = GSVector4i(dty * ps0123).ps32(GSVector4i(dty * ps4567));
movaps(xmm1, xmm0);
mulps(xmm0, xmm6);
mulps(xmm1, xmm7);
cvttps2dq(xmm0, xmm0);
cvttps2dq(xmm1, xmm1);
packssdw(xmm0, xmm1);
movdqa(ptr[&m_local.d.t], xmm0);
}
// xmm4 = dc
// xmm6 = ps0123
// xmm7 = ps4567
// xmm0, xmm1, zmm2, xmm3, xmm5 = free
if(m_sel.iip && m_sel.tfx != 3)
{
// GSVector4 dcx = dc.xxxx();
// GSVector4 dcy = dc.yyyy();
// GSVector4 dcz = dc.zzzz();
movaps(xmm0, xmm4);
movaps(xmm1, xmm4);
shufps(xmm4, xmm4, _MM_SHUFFLE(0, 0, 0, 0));
shufps(xmm0, xmm0, _MM_SHUFFLE(1, 1, 1, 1));
shufps(xmm1, xmm1, _MM_SHUFFLE(2, 2, 2, 2));
// m_local.d.r = GSVector4i(dcx * ps0123).ps32(GSVector4i(dcx * ps4567));
movaps(xmm2, xmm4);
mulps(xmm4, xmm6);
mulps(xmm2, xmm7);
cvttps2dq(xmm4, xmm4);
cvttps2dq(xmm2, xmm2);
packssdw(xmm4, xmm2);
movdqa(ptr[&m_local.d.r], xmm4);
// m_local.d.g = GSVector4i(dcy * ps0123).ps32(GSVector4i(dcy * ps4567));
movaps(xmm2, xmm0);
mulps(xmm0, xmm6);
mulps(xmm2, xmm7);
cvttps2dq(xmm0, xmm0);
cvttps2dq(xmm2, xmm2);
packssdw(xmm0, xmm2);
movdqa(ptr[&m_local.d.g], xmm0);
// m_local.d.b = GSVector4i(dcz * ps0123).ps32(GSVector4i(dcz * ps4567));
movaps(xmm2, xmm1);
mulps(xmm1, xmm6);
mulps(xmm2, xmm7);
cvttps2dq(xmm1, xmm1);
cvttps2dq(xmm2, xmm2);
packssdw(xmm1, xmm2);
movdqa(ptr[&m_local.d.b], xmm1);
}
}
ret();
}
const GSVector4 GPUSetupPrimCodeGenerator::m_shift[3] =
{
GSVector4(8.0f, 8.0f, 8.0f, 8.0f),
GSVector4(0.0f, 1.0f, 2.0f, 3.0f),
GSVector4(4.0f, 5.0f, 6.0f, 7.0f),
};

View File

@ -0,0 +1,40 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GPUScanlineEnvironment.h"
#include "GSFunctionMap.h"
class GPUSetupPrimCodeGenerator : public GSCodeGenerator
{
void operator = (const GPUSetupPrimCodeGenerator&);
GPUScanlineSelector m_sel;
GPUScanlineLocalData& m_local;
void Generate();
public:
GPUSetupPrimCodeGenerator(void* param, uint32 key, void* code, size_t maxsize);
static const GSVector4 m_shift[3];
};

View File

@ -0,0 +1,809 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GPUState.h"
GPUState::GPUState()
: s_n(0)
{
memset(m_status, 0, sizeof(m_status));
for(size_t i = 0; i < countof(m_fpGPUStatusCommandHandlers); i++)
{
m_fpGPUStatusCommandHandlers[i] = &GPUState::SCH_Null;
}
m_fpGPUStatusCommandHandlers[0x00] = &GPUState::SCH_ResetGPU;
m_fpGPUStatusCommandHandlers[0x01] = &GPUState::SCH_ResetCommandBuffer;
m_fpGPUStatusCommandHandlers[0x02] = &GPUState::SCH_ResetIRQ;
m_fpGPUStatusCommandHandlers[0x03] = &GPUState::SCH_DisplayEnable;
m_fpGPUStatusCommandHandlers[0x04] = &GPUState::SCH_DMASetup;
m_fpGPUStatusCommandHandlers[0x05] = &GPUState::SCH_StartOfDisplayArea;
m_fpGPUStatusCommandHandlers[0x06] = &GPUState::SCH_HorizontalDisplayRange;
m_fpGPUStatusCommandHandlers[0x07] = &GPUState::SCH_VerticalDisplayRange;
m_fpGPUStatusCommandHandlers[0x08] = &GPUState::SCH_DisplayMode;
m_fpGPUStatusCommandHandlers[0x10] = &GPUState::SCH_GPUInfo;
m_fpGPUPacketHandler[0] = &GPUState::PH_Command;
m_fpGPUPacketHandler[1] = &GPUState::PH_Polygon;
m_fpGPUPacketHandler[2] = &GPUState::PH_Line;
m_fpGPUPacketHandler[3] = &GPUState::PH_Sprite;
m_fpGPUPacketHandler[4] = &GPUState::PH_Move;
m_fpGPUPacketHandler[5] = &GPUState::PH_Write;
m_fpGPUPacketHandler[6] = &GPUState::PH_Read;
m_fpGPUPacketHandler[7] = &GPUState::PH_Environment;
Reset();
}
GPUState::~GPUState()
{
}
void GPUState::Reset()
{
m_env.Reset();
m_mem.Invalidate(GSVector4i(0, 0, 1024, 512));
memset(&m_v, 0, sizeof(m_v));
}
void GPUState::Flush()
{
FlushPrim();
}
void GPUState::SetPrim(GPUReg* r)
{
if(m_env.PRIM.TYPE != r->PRIM.TYPE)
{
ResetPrim();
}
GPURegPRIM PRIM = r->PRIM;
PRIM.VTX = 0;
switch(r->PRIM.TYPE)
{
case GPU_POLYGON:
PRIM.u32 = (r->PRIM.u32 & 0xF7000000) | 3; // TYPE IIP TME ABE TGE
break;
case GPU_LINE:
PRIM.u32 = (r->PRIM.u32 & 0xF2000000) | 2; // TYPE IIP ABE
PRIM.TGE = 1; // ?
break;
case GPU_SPRITE:
PRIM.u32 = (r->PRIM.u32 & 0xE7000000) | 2; // TYPE TME ABE TGE
break;
}
if(m_env.PRIM.u32 != PRIM.u32)
{
Flush();
m_env.PRIM = PRIM;
}
}
void GPUState::SetCLUT(GPUReg* r)
{
uint32 mask = 0xFFFF0000; // X Y
uint32 value = (m_env.CLUT.u32 & ~mask) | (r->u32 & mask);
if(m_env.CLUT.u32 != value)
{
Flush();
m_env.CLUT.u32 = value;
}
}
void GPUState::SetTPAGE(GPUReg* r)
{
uint32 mask = 0x000001FF; // TP ABR TY TX
uint32 value = (m_env.STATUS.u32 & ~mask) | ((r->u32 >> 16) & mask);
if(m_env.STATUS.u32 != value)
{
Flush();
m_env.STATUS.u32 = value;
}
}
void GPUState::Invalidate(const GSVector4i& r)
{
m_mem.Invalidate(r);
}
void GPUState::WriteData(const uint8* mem, uint32 size)
{
GSPerfMonAutoTimer pmat(&m_perfmon);
size <<= 2;
m_write.Append(mem, size);
int i = 0;
while(i < m_write.bytes)
{
GPUReg* r = (GPUReg*)&m_write.buff[i];
int ret = (this->*m_fpGPUPacketHandler[r->PACKET.TYPE])(r, (m_write.bytes - i) >> 2);
if(ret == 0) return; // need more data
i += ret << 2;
}
m_write.Remove(i);
}
void GPUState::ReadData(uint8* mem, uint32 size)
{
GSPerfMonAutoTimer pmat(&m_perfmon);
int remaining = m_read.bytes - m_read.cur;
int bytes = (int)size << 2;
if(bytes > remaining)
{
// ASSERT(0);
// printf"WARNING: ReadData\n");
// memset(&mem[remaining], 0, bytes - remaining);
bytes = remaining;
}
memcpy(mem, &m_read.buff[m_read.cur], bytes);
m_read.cur += bytes;
if(m_read.cur >= m_read.bytes)
{
m_env.STATUS.IMG = 0;
}
}
void GPUState::WriteStatus(uint32 status)
{
GSPerfMonAutoTimer pmat(&m_perfmon);
uint32 b = status >> 24;
m_status[b] = status;
(this->*m_fpGPUStatusCommandHandlers[b])((GPUReg*)&status);
}
uint32 GPUState::ReadStatus()
{
GSPerfMonAutoTimer pmat(&m_perfmon);
m_env.STATUS.LCF = ~m_env.STATUS.LCF; // ?
return m_env.STATUS.u32;
}
void GPUState::Freeze(GPUFreezeData* data)
{
data->status = m_env.STATUS.u32;
memcpy(data->control, m_status, 256 * 4);
m_mem.ReadRect(GSVector4i(0, 0, 1024, 512), data->vram);
}
void GPUState::Defrost(const GPUFreezeData* data)
{
m_env.STATUS.u32 = data->status;
memcpy(m_status, data->control, 256 * 4);
m_mem.WriteRect(GSVector4i(0, 0, 1024, 512), data->vram);
for(int i = 0; i <= 8; i++)
{
WriteStatus(m_status[i]);
}
}
void GPUState::SCH_Null(GPUReg* r)
{
ASSERT(0);
}
void GPUState::SCH_ResetGPU(GPUReg* r)
{
Reset();
}
void GPUState::SCH_ResetCommandBuffer(GPUReg* r)
{
// ?
}
void GPUState::SCH_ResetIRQ(GPUReg* r)
{
// ?
}
void GPUState::SCH_DisplayEnable(GPUReg* r)
{
m_env.STATUS.DEN = r->DEN.DEN;
}
void GPUState::SCH_DMASetup(GPUReg* r)
{
m_env.STATUS.DMA = r->DMA.DMA;
}
void GPUState::SCH_StartOfDisplayArea(GPUReg* r)
{
m_env.DAREA = r->DAREA;
}
void GPUState::SCH_HorizontalDisplayRange(GPUReg* r)
{
m_env.DHRANGE = r->DHRANGE;
}
void GPUState::SCH_VerticalDisplayRange(GPUReg* r)
{
m_env.DVRANGE = r->DVRANGE;
}
void GPUState::SCH_DisplayMode(GPUReg* r)
{
m_env.STATUS.WIDTH0 = r->DMODE.WIDTH0;
m_env.STATUS.HEIGHT = r->DMODE.HEIGHT;
m_env.STATUS.ISPAL = r->DMODE.ISPAL;
m_env.STATUS.ISRGB24 = r->DMODE.ISRGB24;
m_env.STATUS.ISINTER = r->DMODE.ISINTER;
m_env.STATUS.WIDTH1 = r->DMODE.WIDTH1;
}
void GPUState::SCH_GPUInfo(GPUReg* r)
{
uint32 value = 0;
switch(r->GPUINFO.PARAM)
{
case 0x2:
value = m_env.TWIN.u32;
break;
case 0x0:
case 0x1:
case 0x3:
value = m_env.DRAREATL.u32;
break;
case 0x4:
value = m_env.DRAREABR.u32;
break;
case 0x5:
case 0x6:
value = m_env.DROFF.u32;
break;
case 0x7:
value = 2;
break;
case 0x8:
case 0xf:
value = 0xBFC03720; // ?
break;
default:
ASSERT(0);
break;
}
m_read.RemoveAll();
m_read.Append((uint8*)&value, 4);
m_read.cur = 0;
}
int GPUState::PH_Command(GPUReg* r, int size)
{
switch(r->PACKET.OPTION)
{
case 0: // ???
return 1;
case 1: // clear cache
return 1;
case 2: // fillrect
if(size < 3) return 0;
Flush();
GSVector4i r2;
r2.left = r[1].XY.X;
r2.top = r[1].XY.Y;
r2.right = r2.left + r[2].XY.X;
r2.bottom = r2.top + r[2].XY.Y;
uint16 c = (uint16)(((r[0].RGB.R >> 3) << 10) | ((r[0].RGB.R >> 3) << 5) | (r[0].RGB.R >> 3));
m_mem.FillRect(r2, c);
Invalidate(r2);
Dump("f");
return 3;
}
ASSERT(0);
return 1;
}
int GPUState::PH_Polygon(GPUReg* r, int size)
{
int required = 1;
int vertices = r[0].POLYGON.VTX ? 4 : 3;
required += vertices;
if(r[0].POLYGON.TME) required += vertices;
if(r[0].POLYGON.IIP) required += vertices - 1;
if(size < required) return 0;
//
SetPrim(r);
if(r[0].POLYGON.TME)
{
SetCLUT(&r[2]);
SetTPAGE(&r[r[0].POLYGON.IIP ? 5 : 4]);
}
//
GPUVertex v[4];
for(int i = 0, j = 0; j < vertices; j++)
{
v[j].RGB = r[r[0].POLYGON.IIP ? i : 0].RGB;
if(j == 0 || r[0].POLYGON.IIP) i++;
v[j].XY = r[i++].XY;
if(r[0].POLYGON.TME)
{
v[j].UV.X = r[i].UV.U;
v[j].UV.Y = r[i].UV.V;
i++;
}
}
for(int i = 0; i <= vertices - 3; i++)
{
// TODO: sse
int y0 = v[i + 0].XY.Y;
int y1 = v[i + 1].XY.Y;
int y2 = v[i + 2].XY.Y;
if(std::abs(y0 - y1) >= 512
|| std::abs(y0 - y2) >= 512
|| std::abs(y1 - y2) >= 512)
{
continue;
}
int x0 = v[i + 0].XY.X;
int x1 = v[i + 1].XY.X;
int x2 = v[i + 2].XY.X;
if(std::abs(x0 - x1) >= 1024
|| std::abs(x0 - x2) >= 1024
|| std::abs(x1 - x2) >= 1024)
{
continue;
}
//
for(int j = 0; j < 3; j++)
{
m_v = v[i + j];
VertexKick();
}
}
//
return required;
}
int GPUState::PH_Line(GPUReg* r, int size)
{
int required = 1;
int vertices = 0;
if(r->LINE.PLL)
{
required++;
for(int i = 1; i < size; i++)
{
if((r[i].u32 & 0xf000f000) == 0x50005000)
{
vertices = i - 1;
}
}
if(vertices < 2)
{
return 0;
}
}
else
{
vertices = 2;
}
required += vertices;
if(r->LINE.IIP) required += vertices - 1;
//
SetPrim(r);
//
for(int i = 0, j = 0; j < vertices; j++)
{
if(j >= 2) VertexKick();
m_v.RGB = r[r[0].LINE.IIP ? i : 0].RGB;
if(j == 0 || r[0].LINE.IIP) i++;
m_v.XY = r[i++].XY;
VertexKick();
}
//
return required;
}
int GPUState::PH_Sprite(GPUReg* r, int size)
{
int required = 2;
if(r[0].SPRITE.TME) required++;
if(r[0].SPRITE.SIZE == 0) required++;
if(size < required) return 0;
//
SetPrim(r);
if(r[0].SPRITE.TME)
{
SetCLUT(&r[2]);
}
//
int i = 0;
m_v.RGB = r[i++].RGB;
m_v.XY = r[i++].XY;
if(r[0].SPRITE.TME)
{
m_v.UV.X = r[i].UV.U;
m_v.UV.Y = r[i].UV.V;
i++;
}
VertexKick();
int w = 0;
int h = 0;
switch(r[0].SPRITE.SIZE)
{
case 0: w = r[i].XY.X; h = r[i].XY.Y; i++; break;
case 1: w = h = 1; break;
case 2: w = h = 8; break;
case 3: w = h = 16; break;
default: __assume(0);
}
m_v.XY.X += w;
m_v.XY.Y += h;
if(r[0].SPRITE.TME)
{
m_v.UV.X += w;
m_v.UV.Y += h;
}
VertexKick();
//
return required;
}
int GPUState::PH_Move(GPUReg* r, int size)
{
if(size < 4) return 0;
Flush();
int sx = r[1].XY.X;
int sy = r[1].XY.Y;
int dx = r[2].XY.X;
int dy = r[2].XY.Y;
int w = r[3].XY.X;
int h = r[3].XY.Y;
m_mem.MoveRect(sx, sy, dx, dy, w, h);
Invalidate(GSVector4i(dx, dy, dx + w, dy + h));
// Dump("m");
return 4;
}
int GPUState::PH_Write(GPUReg* r, int size)
{
if(size < 3) return 0;
int w = r[2].XY.X;
int h = r[2].XY.Y;
int required = 3 + ((w * h + 1) >> 1);
if(size < required) return 0;
Flush();
GSVector4i r2;
r2.left = r[1].XY.X;
r2.top = r[1].XY.Y;
r2.right = r2.left + w;
r2.bottom = r2.top + h;
m_mem.WriteRect(r2, (const uint16*)&r[3]);
Invalidate(r2);
Dump("w");
m_perfmon.Put(GSPerfMon::Swizzle, w * h * 2);
return required;
}
int GPUState::PH_Read(GPUReg* r, int size)
{
if(size < 3) return 0;
Flush();
int w = r[2].XY.X;
int h = r[2].XY.Y;
if(w > 0 && h > 0)
{
GSVector4i r2;
r2.left = r[1].XY.X;
r2.top = r[1].XY.Y;
r2.right = r2.left + w;
r2.bottom = r2.top + h;
m_read.bytes = ((w * h + 1) & ~1) * 2;
m_read.cur = 0;
m_read.Reserve(m_read.bytes);
m_mem.ReadRect(r2, (uint16*)m_read.buff);
Dump("r");
}
m_env.STATUS.IMG = 1;
return 3;
}
int GPUState::PH_Environment(GPUReg* r, int size)
{
switch(r->PACKET.OPTION)
{
case 1: // draw mode setting
if(((m_env.STATUS.u32 ^ r->MODE.u32) & 0x7ff) != 0)
{
Flush();
m_env.STATUS.TX = r->MODE.TX;
m_env.STATUS.TY = r->MODE.TY;
m_env.STATUS.ABR = r->MODE.ABR;
m_env.STATUS.TP = r->MODE.TP;
m_env.STATUS.DTD = r->MODE.DTD;
m_env.STATUS.DFE = r->MODE.DFE;
}
return 1;
case 2: // texture window setting
if(((m_env.TWIN.u32 ^ r->TWIN.u32) & 0xfffff) != 0)
{
Flush();
m_env.TWIN = r->TWIN;
}
return 1;
case 3: // set drawing area top left
if(((m_env.DRAREATL.u32 ^ r->DRAREA.u32) & 0xfffff) != 0)
{
Flush();
m_env.DRAREATL = r->DRAREA;
}
return 1;
case 4: // set drawing area bottom right
if(((m_env.DRAREABR.u32 ^ r->DRAREA.u32) & 0xfffff) != 0)
{
Flush();
m_env.DRAREABR = r->DRAREA;
}
return 1;
case 5: // drawing offset
if(((m_env.DROFF.u32 ^ r->DROFF.u32) & 0x3fffff) != 0)
{
Flush();
m_env.DROFF = r->DROFF;
}
return 1;
case 6: // mask setting
if(m_env.STATUS.MD != r->MASK.MD || m_env.STATUS.ME != r->MASK.ME)
{
Flush();
m_env.STATUS.MD = r->MASK.MD;
m_env.STATUS.ME = r->MASK.ME;
}
return 1;
}
ASSERT(0);
return 1;
}
//
GPUState::Buffer::Buffer()
{
bytes = 0;
maxbytes = 4096;
buff = (uint8*)_aligned_malloc(maxbytes, 32);
cur = 0;
}
GPUState::Buffer::~Buffer()
{
_aligned_free(buff);
}
void GPUState::Buffer::Reserve(int size)
{
if(size > maxbytes)
{
int new_maxbytes = (maxbytes + size + 1023) & ~1023;
uint8* new_buff = (uint8*)_aligned_malloc(new_maxbytes, 32);
if(buff != NULL)
{
memcpy(new_buff, buff, maxbytes);
_aligned_free(buff);
}
maxbytes = new_maxbytes;
buff = new_buff;
}
}
void GPUState::Buffer::Append(const uint8* src, int size)
{
Reserve(bytes + (int)size);
memcpy(&buff[bytes], src, size);
bytes += size;
}
void GPUState::Buffer::Remove(int size)
{
ASSERT(size <= bytes);
if(size < bytes)
{
memmove(&buff[0], &buff[size], bytes - size);
bytes -= size;
}
else
{
bytes = 0;
}
#ifdef DEBUG
memset(&buff[bytes], 0xff, maxbytes - bytes);
#endif
}
void GPUState::Buffer::RemoveAll()
{
bytes = 0;
}

View File

@ -0,0 +1,143 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GPU.h"
#include "GPUDrawingEnvironment.h"
#include "GPULocalMemory.h"
#include "GPUVertex.h"
#include "GSAlignedClass.h"
#include "GSUtil.h"
#include "GSPerfMon.h"
class GPUState : public GSAlignedClass<32>
{
typedef void (GPUState::*GPUStatusCommandHandler)(GPUReg* r);
GPUStatusCommandHandler m_fpGPUStatusCommandHandlers[256];
void SCH_Null(GPUReg* r);
void SCH_ResetGPU(GPUReg* r);
void SCH_ResetCommandBuffer(GPUReg* r);
void SCH_ResetIRQ(GPUReg* r);
void SCH_DisplayEnable(GPUReg* r);
void SCH_DMASetup(GPUReg* r);
void SCH_StartOfDisplayArea(GPUReg* r);
void SCH_HorizontalDisplayRange(GPUReg* r);
void SCH_VerticalDisplayRange(GPUReg* r);
void SCH_DisplayMode(GPUReg* r);
void SCH_GPUInfo(GPUReg* r);
typedef int (GPUState::*GPUPacketHandler)(GPUReg* r, int size);
GPUPacketHandler m_fpGPUPacketHandler[8];
int PH_Command(GPUReg* r, int size);
int PH_Polygon(GPUReg* r, int size);
int PH_Line(GPUReg* r, int size);
int PH_Sprite(GPUReg* r, int size);
int PH_Move(GPUReg* r, int size);
int PH_Write(GPUReg* r, int size);
int PH_Read(GPUReg* r, int size);
int PH_Environment(GPUReg* r, int size);
class Buffer
{
public:
int bytes;
int maxbytes;
uint8* buff;
int cur;
public:
Buffer();
~Buffer();
void Reserve(int size);
void Append(const uint8* src, int size);
void Remove(int size);
void RemoveAll();
};
Buffer m_write;
Buffer m_read;
void SetPrim(GPUReg* r);
void SetCLUT(GPUReg* r);
void SetTPAGE(GPUReg* r);
protected:
int s_n;
void Dump(const string& s, uint32 TP, const GSVector4i& r, int inc = true)
{
//if(m_perfmon.GetFrame() < 1000)
//if((m_env.TWIN.u32 & 0xfffff) == 0)
//if(!m_env.STATUS.ME && !m_env.STATUS.MD)
return;
if(inc) s_n++;
//if(s_n < 86) return;
int dir = 1;
#ifdef DEBUG
dir = 2;
#endif
string path = format("c:\\temp%d\\%04d_%s.bmp", dir, s_n, s.c_str());
m_mem.SaveBMP(path, r, TP, m_env.CLUT.X, m_env.CLUT.Y);
}
void Dump(const string& s, int inc = true)
{
Dump(s, 2, GSVector4i(0, 0, 1024, 512), inc);
}
public:
GPUDrawingEnvironment m_env;
GPULocalMemory m_mem;
GPUVertex m_v;
GSPerfMon m_perfmon;
uint32 m_status[256];
public:
GPUState();
virtual ~GPUState();
virtual void Reset();
virtual void Flush();
virtual void FlushPrim() = 0;
virtual void ResetPrim() = 0;
virtual void VertexKick() = 0;
virtual void Invalidate(const GSVector4i& r);
void WriteData(const uint8* mem, uint32 size);
void ReadData(uint8* mem, uint32 size);
void WriteStatus(uint32 status);
uint32 ReadStatus();
void Freeze(GPUFreezeData* data);
void Defrost(const GPUFreezeData* data);
};

View File

@ -0,0 +1,51 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GPU.h"
#include "GSVector.h"
#pragma pack(push, 1)
__aligned(struct, 32) GPUVertex
{
union
{
struct
{
GPURegRGB RGB;
GPURegXY XY;
GPURegXY UV;
};
struct {__m128i m128i;};
struct {__m128 m128;};
};
GPUVertex() {memset(this, 0, sizeof(*this));}
};
struct GPUVertexNull
{
};
#pragma pack(pop)

1768
plugins/GSdx_legacy/GS.cpp Normal file

File diff suppressed because it is too large Load Diff

1300
plugins/GSdx_legacy/GS.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,23 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSAlignedClass.h"

View File

@ -0,0 +1,49 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
template<int i> class GSAlignedClass
{
public:
GSAlignedClass() {}
virtual ~GSAlignedClass() {}
void* operator new (size_t size)
{
return _aligned_malloc(size, i);
}
void operator delete (void* p)
{
_aligned_free(p);
}
void* operator new [] (size_t size)
{
return _aligned_malloc(size, i);
}
void operator delete [] (void* p)
{
_aligned_free(p);
}
};

View File

@ -0,0 +1,48 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSBlock.h"
#if _M_SSE >= 0x501
const GSVector8i GSBlock::m_r16mask(0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15, 0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15);
#else
const GSVector4i GSBlock::m_r16mask(0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15);
#endif
const GSVector4i GSBlock::m_r8mask(0, 4, 2, 6, 8, 12, 10, 14, 1, 5, 3, 7, 9, 13, 11, 15);
const GSVector4i GSBlock::m_r4mask(0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15);
#if _M_SSE >= 0x501
const GSVector8i GSBlock::m_xxxa(0x00008000);
const GSVector8i GSBlock::m_xxbx(0x00007c00);
const GSVector8i GSBlock::m_xgxx(0x000003e0);
const GSVector8i GSBlock::m_rxxx(0x0000001f);
#else
const GSVector4i GSBlock::m_xxxa(0x00008000);
const GSVector4i GSBlock::m_xxbx(0x00007c00);
const GSVector4i GSBlock::m_xgxx(0x000003e0);
const GSVector4i GSBlock::m_rxxx(0x0000001f);
#endif
const GSVector4i GSBlock::m_uw8hmask0(0, 0, 0, 0, 1, 1, 1, 1, 8, 8, 8, 8, 9, 9, 9, 9);
const GSVector4i GSBlock::m_uw8hmask1(2, 2, 2, 2, 3, 3, 3, 3, 10, 10, 10, 10, 11, 11, 11, 11);
const GSVector4i GSBlock::m_uw8hmask2(4, 4, 4, 4, 5, 5, 5, 5, 12, 12, 12, 12, 13, 13, 13, 13);
const GSVector4i GSBlock::m_uw8hmask3(6, 6, 6, 6, 7, 7, 7, 7, 14, 14, 14, 14, 15, 15, 15, 15);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,569 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSCapture.h"
#include "GSPng.h"
#include "GSUtil.h"
#ifdef _WIN32
//
// GSSource
//
#ifdef __INTEL_COMPILER
interface __declspec(uuid("59C193BB-C520-41F3-BC1D-E245B80A86FA"))
#else
[uuid("59C193BB-C520-41F3-BC1D-E245B80A86FA")] interface
#endif
IGSSource : public IUnknown
{
STDMETHOD(DeliverNewSegment)() PURE;
STDMETHOD(DeliverFrame)(const void* bits, int pitch, bool rgba) PURE;
STDMETHOD(DeliverEOS)() PURE;
};
#ifdef __INTEL_COMPILER
class __declspec(uuid("F8BB6F4F-0965-4ED4-BA74-C6A01E6E6C77"))
#else
[uuid("F8BB6F4F-0965-4ED4-BA74-C6A01E6E6C77")] class
#endif
GSSource : public CBaseFilter, private CCritSec, public IGSSource
{
GSVector2i m_size;
REFERENCE_TIME m_atpf;
REFERENCE_TIME m_now;
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv)
{
return
riid == __uuidof(IGSSource) ? GetInterface((IGSSource*)this, ppv) :
__super::NonDelegatingQueryInterface(riid, ppv);
}
class GSSourceOutputPin : public CBaseOutputPin
{
GSVector2i m_size;
vector<CMediaType> m_mts;
public:
GSSourceOutputPin(const GSVector2i& size, REFERENCE_TIME atpf, CBaseFilter* pFilter, CCritSec* pLock, HRESULT& hr, int colorspace)
: CBaseOutputPin("GSSourceOutputPin", pFilter, pLock, &hr, L"Output")
, m_size(size)
{
CMediaType mt;
mt.majortype = MEDIATYPE_Video;
mt.formattype = FORMAT_VideoInfo;
VIDEOINFOHEADER vih;
memset(&vih, 0, sizeof(vih));
vih.AvgTimePerFrame = atpf;
vih.bmiHeader.biSize = sizeof(vih.bmiHeader);
vih.bmiHeader.biWidth = m_size.x;
vih.bmiHeader.biHeight = m_size.y;
// YUY2
mt.subtype = MEDIASUBTYPE_YUY2;
mt.lSampleSize = m_size.x * m_size.y * 2;
vih.bmiHeader.biCompression = '2YUY';
vih.bmiHeader.biPlanes = 1;
vih.bmiHeader.biBitCount = 16;
vih.bmiHeader.biSizeImage = m_size.x * m_size.y * 2;
mt.SetFormat((uint8*)&vih, sizeof(vih));
m_mts.push_back(mt);
// RGB32
mt.subtype = MEDIASUBTYPE_RGB32;
mt.lSampleSize = m_size.x * m_size.y * 4;
vih.bmiHeader.biCompression = BI_RGB;
vih.bmiHeader.biPlanes = 1;
vih.bmiHeader.biBitCount = 32;
vih.bmiHeader.biSizeImage = m_size.x * m_size.y * 4;
mt.SetFormat((uint8*)&vih, sizeof(vih));
if(colorspace == 1) m_mts.insert(m_mts.begin(), mt);
else m_mts.push_back(mt);
}
HRESULT GSSourceOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties)
{
ASSERT(pAlloc && pProperties);
HRESULT hr;
pProperties->cBuffers = 1;
pProperties->cbBuffer = m_mt.lSampleSize;
ALLOCATOR_PROPERTIES Actual;
if(FAILED(hr = pAlloc->SetProperties(pProperties, &Actual)))
{
return hr;
}
if(Actual.cbBuffer < pProperties->cbBuffer)
{
return E_FAIL;
}
ASSERT(Actual.cBuffers == pProperties->cBuffers);
return S_OK;
}
HRESULT CheckMediaType(const CMediaType* pmt)
{
for(vector<CMediaType>::iterator i = m_mts.begin(); i != m_mts.end(); i++)
{
if(i->majortype == pmt->majortype && i->subtype == pmt->subtype)
{
return S_OK;
}
}
return E_FAIL;
}
HRESULT GetMediaType(int i, CMediaType* pmt)
{
CheckPointer(pmt, E_POINTER);
if(i < 0) return E_INVALIDARG;
if(i > 1) return VFW_S_NO_MORE_ITEMS;
*pmt = m_mts[i];
return S_OK;
}
STDMETHODIMP Notify(IBaseFilter* pSender, Quality q)
{
return E_NOTIMPL;
}
const CMediaType& CurrentMediaType()
{
return m_mt;
}
};
GSSourceOutputPin* m_output;
public:
GSSource(int w, int h, float fps, IUnknown* pUnk, HRESULT& hr, int colorspace)
: CBaseFilter(NAME("GSSource"), pUnk, this, __uuidof(this), &hr)
, m_output(NULL)
, m_size(w, h)
, m_atpf((REFERENCE_TIME)(10000000.0f / fps))
, m_now(0)
{
m_output = new GSSourceOutputPin(m_size, m_atpf, this, this, hr, colorspace);
}
virtual ~GSSource()
{
delete m_output;
}
DECLARE_IUNKNOWN;
int GetPinCount()
{
return 1;
}
CBasePin* GetPin(int n)
{
return n == 0 ? m_output : NULL;
}
// IGSSource
STDMETHODIMP DeliverNewSegment()
{
m_now = 0;
return m_output->DeliverNewSegment(0, _I64_MAX, 1.0);
}
STDMETHODIMP DeliverFrame(const void* bits, int pitch, bool rgba)
{
if(!m_output || !m_output->IsConnected())
{
return E_UNEXPECTED;
}
CComPtr<IMediaSample> sample;
if(FAILED(m_output->GetDeliveryBuffer(&sample, NULL, NULL, 0)))
{
return E_FAIL;
}
REFERENCE_TIME start = m_now;
REFERENCE_TIME stop = m_now + m_atpf;
sample->SetTime(&start, &stop);
sample->SetSyncPoint(TRUE);
const CMediaType& mt = m_output->CurrentMediaType();
uint8* src = (uint8*)bits;
uint8* dst = NULL;
sample->GetPointer(&dst);
int w = m_size.x;
int h = m_size.y;
int srcpitch = pitch;
if(mt.subtype == MEDIASUBTYPE_YUY2)
{
int dstpitch = ((VIDEOINFOHEADER*)mt.Format())->bmiHeader.biWidth * 2;
GSVector4 ys(0.257f, 0.504f, 0.098f, 0.0f);
GSVector4 us(-0.148f / 2, -0.291f / 2, 0.439f / 2, 0.0f);
GSVector4 vs(0.439f / 2, -0.368f / 2, -0.071f / 2, 0.0f);
if(!rgba)
{
ys = ys.zyxw();
us = us.zyxw();
vs = vs.zyxw();
}
const GSVector4 offset(16, 128, 16, 128);
for(int j = 0; j < h; j++, dst += dstpitch, src += srcpitch)
{
uint32* s = (uint32*)src;
uint16* d = (uint16*)dst;
for(int i = 0; i < w; i += 2)
{
GSVector4 c0 = GSVector4::rgba32(s[i + 0]);
GSVector4 c1 = GSVector4::rgba32(s[i + 1]);
GSVector4 c2 = c0 + c1;
GSVector4 lo = (c0 * ys).hadd(c2 * us);
GSVector4 hi = (c1 * ys).hadd(c2 * vs);
GSVector4 c = lo.hadd(hi) + offset;
*((uint32*)&d[i]) = GSVector4i(c).rgba32();
}
}
}
else if(mt.subtype == MEDIASUBTYPE_RGB32)
{
int dstpitch = ((VIDEOINFOHEADER*)mt.Format())->bmiHeader.biWidth * 4;
dst += dstpitch * (h - 1);
dstpitch = -dstpitch;
for(int j = 0; j < h; j++, dst += dstpitch, src += srcpitch)
{
if(rgba)
{
#if _M_SSE >= 0x301
GSVector4i* s = (GSVector4i*)src;
GSVector4i* d = (GSVector4i*)dst;
GSVector4i mask(2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15);
for(int i = 0, w4 = w >> 2; i < w4; i++)
{
d[i] = s[i].shuffle8(mask);
}
#else
GSVector4i* s = (GSVector4i*)src;
GSVector4i* d = (GSVector4i*)dst;
for(int i = 0, w4 = w >> 2; i < w4; i++)
{
d[i] = ((s[i] & 0x00ff0000) >> 16) | ((s[i] & 0x000000ff) << 16) | (s[i] & 0x0000ff00);
}
#endif
}
else
{
memcpy(dst, src, w * 4);
}
}
}
else
{
return E_FAIL;
}
if(FAILED(m_output->Deliver(sample)))
{
return E_FAIL;
}
m_now = stop;
return S_OK;
}
STDMETHODIMP DeliverEOS()
{
return m_output->DeliverEndOfStream();
}
};
#define BeginEnumPins(pBaseFilter, pEnumPins, pPin) \
{CComPtr<IEnumPins> pEnumPins; \
if(pBaseFilter && SUCCEEDED(pBaseFilter->EnumPins(&pEnumPins))) \
{ \
for(CComPtr<IPin> pPin; S_OK == pEnumPins->Next(1, &pPin, 0); pPin = NULL) \
{ \
#define EndEnumPins }}}
static IPin* GetFirstPin(IBaseFilter* pBF, PIN_DIRECTION dir)
{
if(!pBF) return(NULL);
BeginEnumPins(pBF, pEP, pPin)
{
PIN_DIRECTION dir2;
pPin->QueryDirection(&dir2);
if(dir == dir2)
{
IPin* pRet = pPin.Detach();
pRet->Release();
return(pRet);
}
}
EndEnumPins
return(NULL);
}
#endif
//
// GSCapture
//
GSCapture::GSCapture()
: m_capturing(false), m_frame(0)
, m_out_dir("/tmp/GSdx_Capture") // FIXME Later add an option
{
m_out_dir = theApp.GetConfig("capture_out_dir", "/tmp/GSdx_Capture");
m_threads = theApp.GetConfig("capture_threads", 4);
#ifdef __linux__
m_compression_level = theApp.GetConfig("png_compression_level", Z_BEST_SPEED);
#endif
}
GSCapture::~GSCapture()
{
EndCapture();
}
bool GSCapture::BeginCapture(float fps, GSVector2i recomendedResolution, float aspect)
{
printf("Recomended resolution: %d x %d, DAR for muxing: %.4f\n", recomendedResolution.x, recomendedResolution.y, aspect);
std::lock_guard<std::recursive_mutex> lock(m_lock);
ASSERT(fps != 0);
EndCapture();
#ifdef _WIN32
GSCaptureDlg dlg;
if(IDOK != dlg.DoModal()) return false;
m_size.x = (dlg.m_width + 7) & ~7;
m_size.y = (dlg.m_height + 7) & ~7;
wstring fn(dlg.m_filename.begin(), dlg.m_filename.end());
//
HRESULT hr;
CComPtr<ICaptureGraphBuilder2> cgb;
CComPtr<IBaseFilter> mux;
if(FAILED(hr = m_graph.CoCreateInstance(CLSID_FilterGraph))
|| FAILED(hr = cgb.CoCreateInstance(CLSID_CaptureGraphBuilder2))
|| FAILED(hr = cgb->SetFiltergraph(m_graph))
|| FAILED(hr = cgb->SetOutputFileName(&MEDIASUBTYPE_Avi, fn.c_str(), &mux, NULL)))
{
return false;
}
m_src = new GSSource(m_size.x, m_size.y, fps, NULL, hr, dlg.m_colorspace);
if (dlg.m_enc==0)
{
if (FAILED(hr = m_graph->AddFilter(m_src, L"Source")))
return false;
if (FAILED(hr = m_graph->ConnectDirect(GetFirstPin(m_src, PINDIR_OUTPUT), GetFirstPin(mux, PINDIR_INPUT), NULL)))
return false;
}
else
{
if(FAILED(hr = m_graph->AddFilter(m_src, L"Source"))
|| FAILED(hr = m_graph->AddFilter(dlg.m_enc, L"Encoder")))
{
return false;
}
if(FAILED(hr = m_graph->ConnectDirect(GetFirstPin(m_src, PINDIR_OUTPUT), GetFirstPin(dlg.m_enc, PINDIR_INPUT), NULL))
|| FAILED(hr = m_graph->ConnectDirect(GetFirstPin(dlg.m_enc, PINDIR_OUTPUT), GetFirstPin(mux, PINDIR_INPUT), NULL)))
{
return false;
}
}
BeginEnumFilters(m_graph, pEF, pBF)
{
CFilterInfo fi;
pBF->QueryFilterInfo(&fi);
wstring s(fi.achName);
printf("Filter [%p]: %s\n", pBF.p, string(s.begin(), s.end()).c_str());
BeginEnumPins(pBF, pEP, pPin)
{
CComPtr<IPin> pPinTo;
pPin->ConnectedTo(&pPinTo);
CPinInfo pi;
pPin->QueryPinInfo(&pi);
wstring s(pi.achName);
printf("- Pin [%p - %p]: %s (%s)\n", pPin.p, pPinTo.p, string(s.begin(), s.end()).c_str(), pi.dir ? "out" : "in");
BeginEnumMediaTypes(pPin, pEMT, pmt)
{
}
EndEnumMediaTypes(pmt)
}
EndEnumPins
}
EndEnumFilters
hr = CComQIPtr<IMediaControl>(m_graph)->Run();
CComQIPtr<IGSSource>(m_src)->DeliverNewSegment();
#elif __linux__
// Note I think it doesn't support multiple depth creation
GSmkdir(m_out_dir.c_str());
// Really cheap recording
m_frame = 0;
// Add option !!!
m_size.x = theApp.GetConfig("capture_resx", 1280);
m_size.y = theApp.GetConfig("capture_resy", 1024);
for(int i = 0; i < m_threads; i++) {
m_workers.push_back(new GSPng::Worker());
}
#endif
m_capturing = true;
return true;
}
bool GSCapture::DeliverFrame(const void* bits, int pitch, bool rgba)
{
std::lock_guard<std::recursive_mutex> lock(m_lock);
if(bits == NULL || pitch == 0)
{
ASSERT(0);
return false;
}
#ifdef _WIN32
if(m_src)
{
CComQIPtr<IGSSource>(m_src)->DeliverFrame(bits, pitch, rgba);
return true;
}
#elif __linux__
std::string out_file = m_out_dir + format("/frame.%010d.png", m_frame);
//GSPng::Save(GSPng::RGB_PNG, out_file, (uint8*)bits, m_size.x, m_size.y, pitch, m_compression_level);
m_workers[m_frame%m_threads]->Push(shared_ptr<GSPng::Transaction>(new GSPng::Transaction(GSPng::RGB_PNG, out_file, static_cast<const uint8*>(bits), m_size.x, m_size.y, pitch, m_compression_level)));
m_frame++;
#endif
return false;
}
bool GSCapture::EndCapture()
{
std::lock_guard<std::recursive_mutex> lock(m_lock);
#ifdef _WIN32
if(m_src)
{
CComQIPtr<IGSSource>(m_src)->DeliverEOS();
m_src = NULL;
}
if(m_graph)
{
CComQIPtr<IMediaControl>(m_graph)->Stop();
m_graph = NULL;
}
#elif __linux__
for(size_t i = 0; i < m_workers.size(); i++) {
m_workers[i]->Wait();
}
m_frame = 0;
#endif
m_capturing = false;
return true;
}

View File

@ -0,0 +1,62 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSVector.h"
#include "GSPng.h"
#ifdef _WIN32
#include "GSCaptureDlg.h"
#endif
class GSCapture
{
std::recursive_mutex m_lock;
bool m_capturing;
GSVector2i m_size;
uint64 m_frame;
std::string m_out_dir;
int m_threads;
#ifdef _WIN32
CComPtr<IGraphBuilder> m_graph;
CComPtr<IBaseFilter> m_src;
#elif __linux__
vector<GSPng::Worker*> m_workers;
int m_compression_level;
#endif
public:
GSCapture();
virtual ~GSCapture();
bool BeginCapture(float fps, GSVector2i recomendedResolution, float aspect);
bool DeliverFrame(const void* bits, int pitch, bool rgba);
bool EndCapture();
bool IsCapturing() {return m_capturing;}
GSVector2i GetSize() {return m_size;}
};

View File

@ -0,0 +1,211 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSdx.h"
#include "GSCaptureDlg.h"
GSCaptureDlg::GSCaptureDlg()
: GSDialog(IDD_CAPTURE)
{
m_width = theApp.GetConfig("CaptureWidth", 640);
m_height = theApp.GetConfig("CaptureHeight", 480);
m_filename = theApp.GetConfig("CaptureFileName", "");
}
int GSCaptureDlg::GetSelCodec(Codec& c)
{
INT_PTR data = 0;
if(ComboBoxGetSelData(IDC_CODECS, data))
{
if(data == 0) return 2;
c = *(Codec*)data;
if(!c.filter)
{
c.moniker->BindToObject(NULL, NULL, __uuidof(IBaseFilter), (void**)&c.filter);
if(!c.filter) return 0;
}
return 1;
}
return 0;
}
void GSCaptureDlg::OnInit()
{
__super::OnInit();
SetTextAsInt(IDC_WIDTH, m_width);
SetTextAsInt(IDC_HEIGHT, m_height);
SetText(IDC_FILENAME, m_filename.c_str());
m_codecs.clear();
_bstr_t selected = theApp.GetConfig("CaptureVideoCodecDisplayName", "").c_str();
ComboBoxAppend(IDC_CODECS, "Uncompressed", 0, true);
ComboBoxAppend(IDC_COLORSPACE, "YUY2", 0, true);
ComboBoxAppend(IDC_COLORSPACE, "RGB32", 1, false);
CoInitialize(0); // this is obviously wrong here, each thread should call this on start, and where is CoUninitalize?
BeginEnumSysDev(CLSID_VideoCompressorCategory, moniker)
{
Codec c;
c.moniker = moniker;
wstring prefix;
LPOLESTR str = NULL;
if(FAILED(moniker->GetDisplayName(NULL, NULL, &str)))
continue;
if(wcsstr(str, L"@device:dmo:")) prefix = L"(DMO) ";
else if(wcsstr(str, L"@device:sw:")) prefix = L"(DS) ";
else if(wcsstr(str, L"@device:cm:")) prefix = L"(VfW) ";
c.DisplayName = str;
CoTaskMemFree(str);
CComPtr<IPropertyBag> pPB;
if(FAILED(moniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pPB)))
continue;
_variant_t var;
if(FAILED(pPB->Read(_bstr_t(_T("FriendlyName")), &var, NULL)))
continue;
c.FriendlyName = prefix + var.bstrVal;
m_codecs.push_back(c);
string s(c.FriendlyName.begin(), c.FriendlyName.end());
ComboBoxAppend(IDC_CODECS, s.c_str(), (LPARAM)&m_codecs.back(), c.DisplayName == selected);
}
EndEnumSysDev
}
bool GSCaptureDlg::OnCommand(HWND hWnd, UINT id, UINT code)
{
if(id == IDC_BROWSE && code == BN_CLICKED)
{
char buff[MAX_PATH] = {0};
OPENFILENAME ofn;
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = m_hWnd;
ofn.lpstrFile = buff;
ofn.nMaxFile = countof(buff);
ofn.lpstrFilter = "Avi files (*.avi)\0*.avi\0";
ofn.Flags = OFN_EXPLORER | OFN_ENABLESIZING | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
strcpy(ofn.lpstrFile, m_filename.c_str());
if(GetSaveFileName(&ofn))
{
m_filename = ofn.lpstrFile;
SetText(IDC_FILENAME, m_filename.c_str());
}
return true;
}
else if(id == IDC_CONFIGURE && code == BN_CLICKED)
{
Codec c;
if(GetSelCodec(c) == 1)
{
if(CComQIPtr<ISpecifyPropertyPages> pSPP = c.filter)
{
CAUUID caGUID;
memset(&caGUID, 0, sizeof(caGUID));
if(SUCCEEDED(pSPP->GetPages(&caGUID)))
{
IUnknown* lpUnk = NULL;
pSPP.QueryInterface(&lpUnk);
OleCreatePropertyFrame(m_hWnd, 0, 0, c.FriendlyName.c_str(), 1, (IUnknown**)&lpUnk, caGUID.cElems, caGUID.pElems, 0, 0, NULL);
lpUnk->Release();
if(caGUID.pElems) CoTaskMemFree(caGUID.pElems);
}
}
else if(CComQIPtr<IAMVfwCompressDialogs> pAMVfWCD = c.filter)
{
if(pAMVfWCD->ShowDialog(VfwCompressDialog_QueryConfig, NULL) == S_OK)
{
pAMVfWCD->ShowDialog(VfwCompressDialog_Config, m_hWnd);
}
}
}
return true;
}
else if(id == IDOK)
{
m_width = GetTextAsInt(IDC_WIDTH);
m_height = GetTextAsInt(IDC_HEIGHT);
m_filename = GetText(IDC_FILENAME);
ComboBoxGetSelData(IDC_COLORSPACE, (INT_PTR)m_colorspace);
Codec c;
int ris = GetSelCodec(c);
if(ris == 0)
{
return false;
}
m_enc = c.filter;
theApp.SetConfig("CaptureWidth", m_width);
theApp.SetConfig("CaptureHeight", m_height);
theApp.SetConfig("CaptureFileName", m_filename.c_str());
if (ris != 2)
{
theApp.SetConfig("CaptureVideoCodecDisplayName", c.DisplayName);
}
else
{
theApp.SetConfig("CaptureVideoCodecDisplayName", "");
}
}
return __super::OnCommand(hWnd, id, code);
}

View File

@ -0,0 +1,54 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSDialog.h"
#include "resource.h"
#include "baseclasses/streams.h"
class GSCaptureDlg : public GSDialog
{
struct Codec
{
CComPtr<IMoniker> moniker;
CComPtr<IBaseFilter> filter;
wstring FriendlyName;
_bstr_t DisplayName;
};
list<Codec> m_codecs;
int GetSelCodec(Codec& c);
protected:
void OnInit();
bool OnCommand(HWND hWnd, UINT id, UINT code);
public:
GSCaptureDlg();
int m_width;
int m_height;
string m_filename;
int m_colorspace;
CComPtr<IBaseFilter> m_enc;
};

View File

@ -0,0 +1,744 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSClut.h"
#include "GSLocalMemory.h"
#define CLUT_ALLOC_SIZE (2 * 4096)
GSClut::GSClut(GSLocalMemory* mem)
: m_mem(mem)
{
uint8* p = (uint8*)vmalloc(CLUT_ALLOC_SIZE, false);
m_clut = (uint16*)&p[0]; // 1k + 1k for mirrored area simulating wrapping memory
m_buff32 = (uint32*)&p[2048]; // 1k
m_buff64 = (uint64*)&p[4096]; // 2k
m_write.dirty = true;
m_read.dirty = true;
for(int i = 0; i < 16; i++)
{
for(int j = 0; j < 64; j++)
{
m_wc[0][i][j] = &GSClut::WriteCLUT_NULL;
m_wc[1][i][j] = &GSClut::WriteCLUT_NULL;
}
}
m_wc[0][PSM_PSMCT32][PSM_PSMT8] = &GSClut::WriteCLUT32_I8_CSM1;
m_wc[0][PSM_PSMCT32][PSM_PSMT8H] = &GSClut::WriteCLUT32_I8_CSM1;
m_wc[0][PSM_PSMCT32][PSM_PSMT4] = &GSClut::WriteCLUT32_I4_CSM1;
m_wc[0][PSM_PSMCT32][PSM_PSMT4HL] = &GSClut::WriteCLUT32_I4_CSM1;
m_wc[0][PSM_PSMCT32][PSM_PSMT4HH] = &GSClut::WriteCLUT32_I4_CSM1;
m_wc[0][PSM_PSMCT24][PSM_PSMT8] = &GSClut::WriteCLUT32_I8_CSM1;
m_wc[0][PSM_PSMCT24][PSM_PSMT8H] = &GSClut::WriteCLUT32_I8_CSM1;
m_wc[0][PSM_PSMCT24][PSM_PSMT4] = &GSClut::WriteCLUT32_I4_CSM1;
m_wc[0][PSM_PSMCT24][PSM_PSMT4HL] = &GSClut::WriteCLUT32_I4_CSM1;
m_wc[0][PSM_PSMCT24][PSM_PSMT4HH] = &GSClut::WriteCLUT32_I4_CSM1;
m_wc[0][PSM_PSMCT16][PSM_PSMT8] = &GSClut::WriteCLUT16_I8_CSM1;
m_wc[0][PSM_PSMCT16][PSM_PSMT8H] = &GSClut::WriteCLUT16_I8_CSM1;
m_wc[0][PSM_PSMCT16][PSM_PSMT4] = &GSClut::WriteCLUT16_I4_CSM1;
m_wc[0][PSM_PSMCT16][PSM_PSMT4HL] = &GSClut::WriteCLUT16_I4_CSM1;
m_wc[0][PSM_PSMCT16][PSM_PSMT4HH] = &GSClut::WriteCLUT16_I4_CSM1;
m_wc[0][PSM_PSMCT16S][PSM_PSMT8] = &GSClut::WriteCLUT16S_I8_CSM1;
m_wc[0][PSM_PSMCT16S][PSM_PSMT8H] = &GSClut::WriteCLUT16S_I8_CSM1;
m_wc[0][PSM_PSMCT16S][PSM_PSMT4] = &GSClut::WriteCLUT16S_I4_CSM1;
m_wc[0][PSM_PSMCT16S][PSM_PSMT4HL] = &GSClut::WriteCLUT16S_I4_CSM1;
m_wc[0][PSM_PSMCT16S][PSM_PSMT4HH] = &GSClut::WriteCLUT16S_I4_CSM1;
m_wc[1][PSM_PSMCT32][PSM_PSMT8] = &GSClut::WriteCLUT32_CSM2<256>;
m_wc[1][PSM_PSMCT32][PSM_PSMT8H] = &GSClut::WriteCLUT32_CSM2<256>;
m_wc[1][PSM_PSMCT32][PSM_PSMT4] = &GSClut::WriteCLUT32_CSM2<16>;
m_wc[1][PSM_PSMCT32][PSM_PSMT4HL] = &GSClut::WriteCLUT32_CSM2<16>;
m_wc[1][PSM_PSMCT32][PSM_PSMT4HH] = &GSClut::WriteCLUT32_CSM2<16>;
m_wc[1][PSM_PSMCT24][PSM_PSMT8] = &GSClut::WriteCLUT32_CSM2<256>;
m_wc[1][PSM_PSMCT24][PSM_PSMT8H] = &GSClut::WriteCLUT32_CSM2<256>;
m_wc[1][PSM_PSMCT24][PSM_PSMT4] = &GSClut::WriteCLUT32_CSM2<16>;
m_wc[1][PSM_PSMCT24][PSM_PSMT4HL] = &GSClut::WriteCLUT32_CSM2<16>;
m_wc[1][PSM_PSMCT24][PSM_PSMT4HH] = &GSClut::WriteCLUT32_CSM2<16>;
m_wc[1][PSM_PSMCT16][PSM_PSMT8] = &GSClut::WriteCLUT16_CSM2<256>;
m_wc[1][PSM_PSMCT16][PSM_PSMT8H] = &GSClut::WriteCLUT16_CSM2<256>;
m_wc[1][PSM_PSMCT16][PSM_PSMT4] = &GSClut::WriteCLUT16_CSM2<16>;
m_wc[1][PSM_PSMCT16][PSM_PSMT4HL] = &GSClut::WriteCLUT16_CSM2<16>;
m_wc[1][PSM_PSMCT16][PSM_PSMT4HH] = &GSClut::WriteCLUT16_CSM2<16>;
m_wc[1][PSM_PSMCT16S][PSM_PSMT8] = &GSClut::WriteCLUT16S_CSM2<256>;
m_wc[1][PSM_PSMCT16S][PSM_PSMT8H] = &GSClut::WriteCLUT16S_CSM2<256>;
m_wc[1][PSM_PSMCT16S][PSM_PSMT4] = &GSClut::WriteCLUT16S_CSM2<16>;
m_wc[1][PSM_PSMCT16S][PSM_PSMT4HL] = &GSClut::WriteCLUT16S_CSM2<16>;
m_wc[1][PSM_PSMCT16S][PSM_PSMT4HH] = &GSClut::WriteCLUT16S_CSM2<16>;
}
GSClut::~GSClut()
{
vmfree(m_clut, CLUT_ALLOC_SIZE);
}
void GSClut::Invalidate()
{
m_write.dirty = true;
}
bool GSClut::WriteTest(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
switch(TEX0.CLD)
{
case 0: return false;
case 1: break;
case 2: m_CBP[0] = TEX0.CBP; break;
case 3: m_CBP[1] = TEX0.CBP; break;
case 4: if(m_CBP[0] == TEX0.CBP) return false; m_CBP[0] = TEX0.CBP; break;
case 5: if(m_CBP[1] == TEX0.CBP) return false; m_CBP[1] = TEX0.CBP; break;
case 6: ASSERT(0); return false; // ffx2 menu
case 7: ASSERT(0); return false; // ford mustang racing // Bouken Jidai Katsugeki Goemon
default: __assume(0);
}
return m_write.IsDirty(TEX0, TEXCLUT);
}
void GSClut::Write(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
m_write.TEX0 = TEX0;
m_write.TEXCLUT = TEXCLUT;
m_write.dirty = false;
m_read.dirty = true;
(this->*m_wc[TEX0.CSM][TEX0.CPSM][TEX0.PSM])(TEX0, TEXCLUT);
// Mirror write to other half of buffer to simulate wrapping memory
int offset = (TEX0.CSA & (TEX0.CPSM < PSM_PSMCT16 ? 15 : 31)) * 16;
if(TEX0.PSM == PSM_PSMT8 || TEX0.PSM == PSM_PSMT8H)
{
int size = TEX0.CPSM < PSM_PSMCT16 ? 512 : 256;
memcpy(m_clut + 512 + offset, m_clut + offset, sizeof(*m_clut) * min(size, 512 - offset));
memcpy(m_clut, m_clut + 512, sizeof(*m_clut) * max(0, size + offset - 512));
}
else
{
int size = 16;
memcpy(m_clut + 512 + offset, m_clut + offset, sizeof(*m_clut) * size);
if(TEX0.CPSM < PSM_PSMCT16)
{
memcpy(m_clut + 512 + 256 + offset, m_clut + 256 + offset, sizeof(*m_clut) * size);
}
}
}
void GSClut::WriteCLUT32_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
ALIGN_STACK(32);
WriteCLUT_T32_I8_CSM1((uint32*)m_mem->BlockPtr32(0, 0, TEX0.CBP, 1), m_clut + ((TEX0.CSA & 15) << 4));
}
void GSClut::WriteCLUT32_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
ALIGN_STACK(32);
WriteCLUT_T32_I4_CSM1((uint32*)m_mem->BlockPtr32(0, 0, TEX0.CBP, 1), m_clut + ((TEX0.CSA & 15) << 4));
}
void GSClut::WriteCLUT16_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
WriteCLUT_T16_I8_CSM1((uint16*)m_mem->BlockPtr16(0, 0, TEX0.CBP, 1), m_clut + (TEX0.CSA << 4));
}
void GSClut::WriteCLUT16_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
WriteCLUT_T16_I4_CSM1((uint16*)m_mem->BlockPtr16(0, 0, TEX0.CBP, 1), m_clut + (TEX0.CSA << 4));
}
void GSClut::WriteCLUT16S_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
WriteCLUT_T16_I8_CSM1((uint16*)m_mem->BlockPtr16S(0, 0, TEX0.CBP, 1), m_clut + (TEX0.CSA << 4));
}
void GSClut::WriteCLUT16S_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
WriteCLUT_T16_I4_CSM1((uint16*)m_mem->BlockPtr16S(0, 0, TEX0.CBP, 1), m_clut + (TEX0.CSA << 4));
}
template<int n> void GSClut::WriteCLUT32_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
GSOffset* off = m_mem->GetOffset(TEX0.CBP, TEXCLUT.CBW, PSM_PSMCT32);
uint32* RESTRICT s = &m_mem->m_vm32[off->pixel.row[TEXCLUT.COV]];
int* RESTRICT col = &off->pixel.col[0][TEXCLUT.COU << 4];
uint16* RESTRICT clut = m_clut + ((TEX0.CSA & 15) << 4);
for(int i = 0; i < n; i++)
{
uint32 c = s[col[i]];
clut[i] = (uint16)(c & 0xffff);
clut[i + 256] = (uint16)(c >> 16);
}
}
template<int n> void GSClut::WriteCLUT16_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
GSOffset* off = m_mem->GetOffset(TEX0.CBP, TEXCLUT.CBW, PSM_PSMCT16);
uint16* RESTRICT s = &m_mem->m_vm16[off->pixel.row[TEXCLUT.COV]];
int* RESTRICT col = &off->pixel.col[0][TEXCLUT.COU << 4];
uint16* RESTRICT clut = m_clut + (TEX0.CSA << 4);
for(int i = 0; i < n; i++)
{
clut[i] = s[col[i]];
}
}
template<int n> void GSClut::WriteCLUT16S_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
GSOffset* off = m_mem->GetOffset(TEX0.CBP, TEXCLUT.CBW, PSM_PSMCT16S);
uint16* RESTRICT s = &m_mem->m_vm16[off->pixel.row[TEXCLUT.COV]];
int* RESTRICT col = &off->pixel.col[0][TEXCLUT.COU << 4];
uint16* RESTRICT clut = m_clut + (TEX0.CSA << 4);
for(int i = 0; i < n; i++)
{
clut[i] = s[col[i]];
}
}
#if 0
void GSClut::Read(const GIFRegTEX0& TEX0)
{
if(m_read.IsDirty(TEX0))
{
m_read.TEX0 = TEX0;
m_read.dirty = false;
uint16* clut = m_clut;
if(TEX0.CPSM == PSM_PSMCT32 || TEX0.CPSM == PSM_PSMCT24)
{
switch(TEX0.PSM)
{
case PSM_PSMT8:
case PSM_PSMT8H:
clut += (TEX0.CSA & 15) << 4;
ReadCLUT_T32_I8(clut, m_buff32);
break;
case PSM_PSMT4:
case PSM_PSMT4HL:
case PSM_PSMT4HH:
clut += (TEX0.CSA & 15) << 4;
ReadCLUT_T32_I4(clut, m_buff32, m_buff64);
break;
}
}
else if(TEX0.CPSM == PSM_PSMCT16 || TEX0.CPSM == PSM_PSMCT16S)
{
switch(TEX0.PSM)
{
case PSM_PSMT8:
case PSM_PSMT8H:
clut += TEX0.CSA << 4;
ReadCLUT_T16_I8(clut, m_buff32);
break;
case PSM_PSMT4:
case PSM_PSMT4HL:
case PSM_PSMT4HH:
clut += TEX0.CSA << 4;
ReadCLUT_T16_I4(clut, m_buff32, m_buff64);
break;
}
}
}
}
#endif
void GSClut::Read32(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA)
{
if(m_read.IsDirty(TEX0, TEXA))
{
m_read.TEX0 = TEX0;
m_read.TEXA = TEXA;
m_read.dirty = false;
m_read.adirty = true;
uint16* clut = m_clut;
if(TEX0.CPSM == PSM_PSMCT32 || TEX0.CPSM == PSM_PSMCT24)
{
switch(TEX0.PSM)
{
case PSM_PSMT8:
case PSM_PSMT8H:
clut += (TEX0.CSA & 15) << 4; // disney golf title screen
ReadCLUT_T32_I8(clut, m_buff32);
break;
case PSM_PSMT4:
case PSM_PSMT4HL:
case PSM_PSMT4HH:
clut += (TEX0.CSA & 15) << 4;
// TODO: merge these functions
ReadCLUT_T32_I4(clut, m_buff32);
ExpandCLUT64_T32_I8(m_buff32, (uint64*)m_buff64); // sw renderer does not need m_buff64 anymore
break;
}
}
else if(TEX0.CPSM == PSM_PSMCT16 || TEX0.CPSM == PSM_PSMCT16S)
{
switch(TEX0.PSM)
{
case PSM_PSMT8:
case PSM_PSMT8H:
clut += TEX0.CSA << 4;
Expand16(clut, m_buff32, 256, TEXA);
break;
case PSM_PSMT4:
case PSM_PSMT4HL:
case PSM_PSMT4HH:
clut += TEX0.CSA << 4;
// TODO: merge these functions
Expand16(clut, m_buff32, 16, TEXA);
ExpandCLUT64_T32_I8(m_buff32, (uint64*)m_buff64); // sw renderer does not need m_buff64 anymore
break;
}
}
}
}
void GSClut::GetAlphaMinMax32(int& amin, int& amax)
{
// call only after Read32
ASSERT(!m_read.dirty);
if(m_read.adirty)
{
m_read.adirty = false;
if(GSLocalMemory::m_psm[m_read.TEX0.CPSM].trbpp == 24 && m_read.TEXA.AEM == 0)
{
m_read.amin = m_read.TEXA.TA0;
m_read.amax = m_read.TEXA.TA0;
}
else
{
const GSVector4i* p = (const GSVector4i*)m_buff32;
GSVector4i amin, amax;
if(GSLocalMemory::m_psm[m_read.TEX0.PSM].pal == 256)
{
amin = GSVector4i::xffffffff();
amax = GSVector4i::zero();
for(int i = 0; i < 16; i++)
{
GSVector4i v0 = (p[i * 4 + 0] >> 24).ps32(p[i * 4 + 1] >> 24);
GSVector4i v1 = (p[i * 4 + 2] >> 24).ps32(p[i * 4 + 3] >> 24);
GSVector4i v2 = v0.pu16(v1);
amin = amin.min_u8(v2);
amax = amax.max_u8(v2);
}
}
else
{
ASSERT(GSLocalMemory::m_psm[m_read.TEX0.PSM].pal == 16);
GSVector4i v0 = (p[0] >> 24).ps32(p[1] >> 24);
GSVector4i v1 = (p[2] >> 24).ps32(p[3] >> 24);
GSVector4i v2 = v0.pu16(v1);
amin = v2;
amax = v2;
}
amin = amin.min_u8(amin.zwxy());
amax = amax.max_u8(amax.zwxy());
amin = amin.min_u8(amin.zwxyl());
amax = amax.max_u8(amax.zwxyl());
amin = amin.min_u8(amin.yxwzl());
amax = amax.max_u8(amax.yxwzl());
GSVector4i v0 = amin.upl8(amax).u8to16();
GSVector4i v1 = v0.yxwz();
m_read.amin = v0.min_i16(v1).extract16<0>();
m_read.amax = v0.max_i16(v1).extract16<1>();
}
}
amin = m_read.amin;
amax = m_read.amax;
}
//
void GSClut::WriteCLUT_T32_I8_CSM1(const uint32* RESTRICT src, uint16* RESTRICT clut)
{
// 4 blocks
for(int i = 0; i < 64; i += 16)
{
WriteCLUT_T32_I4_CSM1(&src[i + 0], &clut[i * 2 + 0]);
WriteCLUT_T32_I4_CSM1(&src[i + 64], &clut[i * 2 + 16]);
WriteCLUT_T32_I4_CSM1(&src[i + 128], &clut[i * 2 + 128]);
WriteCLUT_T32_I4_CSM1(&src[i + 192], &clut[i * 2 + 144]);
}
}
__forceinline void GSClut::WriteCLUT_T32_I4_CSM1(const uint32* RESTRICT src, uint16* RESTRICT clut)
{
// 1 block
#if _M_SSE >= 0x501
GSVector8i* s = (GSVector8i*)src;
GSVector8i* d = (GSVector8i*)clut;
GSVector8i v0 = s[0].acbd();
GSVector8i v1 = s[1].acbd();
GSVector8i::sw16(v0, v1);
GSVector8i::sw16(v0, v1);
GSVector8i::sw16(v0, v1);
d[0] = v0;
d[16] = v1;
#else
GSVector4i* s = (GSVector4i*)src;
GSVector4i* d = (GSVector4i*)clut;
GSVector4i v0 = s[0];
GSVector4i v1 = s[1];
GSVector4i v2 = s[2];
GSVector4i v3 = s[3];
GSVector4i::sw16(v0, v1, v2, v3);
GSVector4i::sw32(v0, v1, v2, v3);
GSVector4i::sw16(v0, v2, v1, v3);
d[0] = v0;
d[1] = v2;
d[32] = v1;
d[33] = v3;
#endif
}
void GSClut::WriteCLUT_T16_I8_CSM1(const uint16* RESTRICT src, uint16* RESTRICT clut)
{
// 2 blocks
GSVector4i* s = (GSVector4i*)src;
GSVector4i* d = (GSVector4i*)clut;
for(int i = 0; i < 32; i += 4)
{
GSVector4i v0 = s[i + 0];
GSVector4i v1 = s[i + 1];
GSVector4i v2 = s[i + 2];
GSVector4i v3 = s[i + 3];
GSVector4i::sw16(v0, v1, v2, v3);
GSVector4i::sw32(v0, v1, v2, v3);
GSVector4i::sw16(v0, v2, v1, v3);
d[i + 0] = v0;
d[i + 1] = v2;
d[i + 2] = v1;
d[i + 3] = v3;
}
}
__forceinline void GSClut::WriteCLUT_T16_I4_CSM1(const uint16* RESTRICT src, uint16* RESTRICT clut)
{
// 1 block (half)
for(int i = 0; i < 16; i++)
{
clut[i] = src[clutTableT16I4[i]];
}
}
void GSClut::ReadCLUT_T32_I8(const uint16* RESTRICT clut, uint32* RESTRICT dst)
{
for(int i = 0; i < 256; i += 16)
{
ReadCLUT_T32_I4(&clut[i], &dst[i]);
}
}
__forceinline void GSClut::ReadCLUT_T32_I4(const uint16* RESTRICT clut, uint32* RESTRICT dst)
{
GSVector4i* s = (GSVector4i*)clut;
GSVector4i* d = (GSVector4i*)dst;
GSVector4i v0 = s[0];
GSVector4i v1 = s[1];
GSVector4i v2 = s[32];
GSVector4i v3 = s[33];
GSVector4i::sw16(v0, v2, v1, v3);
d[0] = v0;
d[1] = v1;
d[2] = v2;
d[3] = v3;
}
#if 0
__forceinline void GSClut::ReadCLUT_T32_I4(const uint16* RESTRICT clut, uint32* RESTRICT dst32, uint64* RESTRICT dst64)
{
GSVector4i* s = (GSVector4i*)clut;
GSVector4i* d32 = (GSVector4i*)dst32;
GSVector4i* d64 = (GSVector4i*)dst64;
GSVector4i s0 = s[0];
GSVector4i s1 = s[1];
GSVector4i s2 = s[32];
GSVector4i s3 = s[33];
GSVector4i::sw16(s0, s2, s1, s3);
d32[0] = s0;
d32[1] = s1;
d32[2] = s2;
d32[3] = s3;
ExpandCLUT64_T32(s0, s0, s1, s2, s3, &d64[0]);
ExpandCLUT64_T32(s1, s0, s1, s2, s3, &d64[32]);
ExpandCLUT64_T32(s2, s0, s1, s2, s3, &d64[64]);
ExpandCLUT64_T32(s3, s0, s1, s2, s3, &d64[96]);
}
#endif
#if 0
void GSClut::ReadCLUT_T16_I8(const uint16* RESTRICT clut, uint32* RESTRICT dst)
{
for(int i = 0; i < 256; i += 16)
{
ReadCLUT_T16_I4(&clut[i], &dst[i]);
}
}
#endif
#if 0
__forceinline void GSClut::ReadCLUT_T16_I4(const uint16* RESTRICT clut, uint32* RESTRICT dst)
{
GSVector4i* s = (GSVector4i*)clut;
GSVector4i* d = (GSVector4i*)dst;
GSVector4i v0 = s[0];
GSVector4i v1 = s[1];
d[0] = v0.upl16();
d[1] = v0.uph16();
d[2] = v1.upl16();
d[3] = v1.uph16();
}
#endif
#if 0
__forceinline void GSClut::ReadCLUT_T16_I4(const uint16* RESTRICT clut, uint32* RESTRICT dst32, uint64* RESTRICT dst64)
{
GSVector4i* s = (GSVector4i*)clut;
GSVector4i* d32 = (GSVector4i*)dst32;
GSVector4i* d64 = (GSVector4i*)dst64;
GSVector4i v0 = s[0];
GSVector4i v1 = s[1];
GSVector4i s0 = v0.upl16();
GSVector4i s1 = v0.uph16();
GSVector4i s2 = v1.upl16();
GSVector4i s3 = v1.uph16();
d32[0] = s0;
d32[1] = s1;
d32[2] = s2;
d32[3] = s3;
ExpandCLUT64_T16(s0, s0, s1, s2, s3, &d64[0]);
ExpandCLUT64_T16(s1, s0, s1, s2, s3, &d64[32]);
ExpandCLUT64_T16(s2, s0, s1, s2, s3, &d64[64]);
ExpandCLUT64_T16(s3, s0, s1, s2, s3, &d64[96]);
}
#endif
void GSClut::ExpandCLUT64_T32_I8(const uint32* RESTRICT src, uint64* RESTRICT dst)
{
GSVector4i* s = (GSVector4i*)src;
GSVector4i* d = (GSVector4i*)dst;
GSVector4i s0 = s[0];
GSVector4i s1 = s[1];
GSVector4i s2 = s[2];
GSVector4i s3 = s[3];
ExpandCLUT64_T32(s0, s0, s1, s2, s3, &d[0]);
ExpandCLUT64_T32(s1, s0, s1, s2, s3, &d[32]);
ExpandCLUT64_T32(s2, s0, s1, s2, s3, &d[64]);
ExpandCLUT64_T32(s3, s0, s1, s2, s3, &d[96]);
}
__forceinline void GSClut::ExpandCLUT64_T32(const GSVector4i& hi, const GSVector4i& lo0, const GSVector4i& lo1, const GSVector4i& lo2, const GSVector4i& lo3, GSVector4i* dst)
{
ExpandCLUT64_T32(hi.xxxx(), lo0, &dst[0]);
ExpandCLUT64_T32(hi.xxxx(), lo1, &dst[2]);
ExpandCLUT64_T32(hi.xxxx(), lo2, &dst[4]);
ExpandCLUT64_T32(hi.xxxx(), lo3, &dst[6]);
ExpandCLUT64_T32(hi.yyyy(), lo0, &dst[8]);
ExpandCLUT64_T32(hi.yyyy(), lo1, &dst[10]);
ExpandCLUT64_T32(hi.yyyy(), lo2, &dst[12]);
ExpandCLUT64_T32(hi.yyyy(), lo3, &dst[14]);
ExpandCLUT64_T32(hi.zzzz(), lo0, &dst[16]);
ExpandCLUT64_T32(hi.zzzz(), lo1, &dst[18]);
ExpandCLUT64_T32(hi.zzzz(), lo2, &dst[20]);
ExpandCLUT64_T32(hi.zzzz(), lo3, &dst[22]);
ExpandCLUT64_T32(hi.wwww(), lo0, &dst[24]);
ExpandCLUT64_T32(hi.wwww(), lo1, &dst[26]);
ExpandCLUT64_T32(hi.wwww(), lo2, &dst[28]);
ExpandCLUT64_T32(hi.wwww(), lo3, &dst[30]);
}
__forceinline void GSClut::ExpandCLUT64_T32(const GSVector4i& hi, const GSVector4i& lo, GSVector4i* dst)
{
dst[0] = lo.upl32(hi);
dst[1] = lo.uph32(hi);
}
#if 0
void GSClut::ExpandCLUT64_T16_I8(const uint32* RESTRICT src, uint64* RESTRICT dst)
{
GSVector4i* s = (GSVector4i*)src;
GSVector4i* d = (GSVector4i*)dst;
GSVector4i s0 = s[0];
GSVector4i s1 = s[1];
GSVector4i s2 = s[2];
GSVector4i s3 = s[3];
ExpandCLUT64_T16(s0, s0, s1, s2, s3, &d[0]);
ExpandCLUT64_T16(s1, s0, s1, s2, s3, &d[32]);
ExpandCLUT64_T16(s2, s0, s1, s2, s3, &d[64]);
ExpandCLUT64_T16(s3, s0, s1, s2, s3, &d[96]);
}
#endif
__forceinline void GSClut::ExpandCLUT64_T16(const GSVector4i& hi, const GSVector4i& lo0, const GSVector4i& lo1, const GSVector4i& lo2, const GSVector4i& lo3, GSVector4i* dst)
{
ExpandCLUT64_T16(hi.xxxx(), lo0, &dst[0]);
ExpandCLUT64_T16(hi.xxxx(), lo1, &dst[2]);
ExpandCLUT64_T16(hi.xxxx(), lo2, &dst[4]);
ExpandCLUT64_T16(hi.xxxx(), lo3, &dst[6]);
ExpandCLUT64_T16(hi.yyyy(), lo0, &dst[8]);
ExpandCLUT64_T16(hi.yyyy(), lo1, &dst[10]);
ExpandCLUT64_T16(hi.yyyy(), lo2, &dst[12]);
ExpandCLUT64_T16(hi.yyyy(), lo3, &dst[14]);
ExpandCLUT64_T16(hi.zzzz(), lo0, &dst[16]);
ExpandCLUT64_T16(hi.zzzz(), lo1, &dst[18]);
ExpandCLUT64_T16(hi.zzzz(), lo2, &dst[20]);
ExpandCLUT64_T16(hi.zzzz(), lo3, &dst[22]);
ExpandCLUT64_T16(hi.wwww(), lo0, &dst[24]);
ExpandCLUT64_T16(hi.wwww(), lo1, &dst[26]);
ExpandCLUT64_T16(hi.wwww(), lo2, &dst[28]);
ExpandCLUT64_T16(hi.wwww(), lo3, &dst[30]);
}
__forceinline void GSClut::ExpandCLUT64_T16(const GSVector4i& hi, const GSVector4i& lo, GSVector4i* dst)
{
dst[0] = lo.upl16(hi);
dst[1] = lo.uph16(hi);
}
// TODO
static const GSVector4i s_bm(0x00007c00);
static const GSVector4i s_gm(0x000003e0);
static const GSVector4i s_rm(0x0000001f);
void GSClut::Expand16(const uint16* RESTRICT src, uint32* RESTRICT dst, int w, const GIFRegTEXA& TEXA)
{
ASSERT((w & 7) == 0);
const GSVector4i rm = s_rm;
const GSVector4i gm = s_gm;
const GSVector4i bm = s_bm;
GSVector4i TA0(TEXA.TA0 << 24);
GSVector4i TA1(TEXA.TA1 << 24);
GSVector4i c, cl, ch;
const GSVector4i* s = (const GSVector4i*)src;
GSVector4i* d = (GSVector4i*)dst;
if(!TEXA.AEM)
{
for(int i = 0, j = w >> 3; i < j; i++)
{
c = s[i];
cl = c.upl16(c);
ch = c.uph16(c);
d[i * 2 + 0] = ((cl & rm) << 3) | ((cl & gm) << 6) | ((cl & bm) << 9) | TA0.blend8(TA1, cl.sra16(15));
d[i * 2 + 1] = ((ch & rm) << 3) | ((ch & gm) << 6) | ((ch & bm) << 9) | TA0.blend8(TA1, ch.sra16(15));
}
}
else
{
for(int i = 0, j = w >> 3; i < j; i++)
{
c = s[i];
cl = c.upl16(c);
ch = c.uph16(c);
d[i * 2 + 0] = ((cl & rm) << 3) | ((cl & gm) << 6) | ((cl & bm) << 9) | TA0.blend8(TA1, cl.sra16(15)).andnot(cl == GSVector4i::zero());
d[i * 2 + 1] = ((ch & rm) << 3) | ((ch & gm) << 6) | ((ch & bm) << 9) | TA0.blend8(TA1, ch.sra16(15)).andnot(ch == GSVector4i::zero());
}
}
}
//
bool GSClut::WriteState::IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
return dirty || !GSVector4i::load<true>(this).eq(GSVector4i::load(&TEX0, &TEXCLUT));
}
bool GSClut::ReadState::IsDirty(const GIFRegTEX0& TEX0)
{
return dirty || !GSVector4i::load<true>(this).eq(GSVector4i::load(&TEX0, &this->TEXA));
}
bool GSClut::ReadState::IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA)
{
return dirty || !GSVector4i::load<true>(this).eq(GSVector4i::load(&TEX0, &TEXA));
}

View File

@ -0,0 +1,110 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GS.h"
#include "GSVector.h"
#include "GSTables.h"
#include "GSAlignedClass.h"
class GSLocalMemory;
__aligned(class, 32) GSClut : public GSAlignedClass<32>
{
GSLocalMemory* m_mem;
uint32 m_CBP[2];
uint16* m_clut;
uint32* m_buff32;
uint64* m_buff64;
__aligned(struct, 32) WriteState
{
GIFRegTEX0 TEX0;
GIFRegTEXCLUT TEXCLUT;
bool dirty;
bool IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
} m_write;
__aligned(struct, 32) ReadState
{
GIFRegTEX0 TEX0;
GIFRegTEXA TEXA;
bool dirty;
bool adirty;
int amin, amax;
bool IsDirty(const GIFRegTEX0& TEX0);
bool IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA);
} m_read;
typedef void (GSClut::*writeCLUT)(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
writeCLUT m_wc[2][16][64];
void WriteCLUT32_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
void WriteCLUT32_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
void WriteCLUT16_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
void WriteCLUT16_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
void WriteCLUT16S_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
void WriteCLUT16S_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
template<int n> void WriteCLUT32_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
template<int n> void WriteCLUT16_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
template<int n> void WriteCLUT16S_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
void WriteCLUT_NULL(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) {} // xenosaga 3, bios
static void WriteCLUT_T32_I8_CSM1(const uint32* RESTRICT src, uint16* RESTRICT clut);
static void WriteCLUT_T32_I4_CSM1(const uint32* RESTRICT src, uint16* RESTRICT clut);
static void WriteCLUT_T16_I8_CSM1(const uint16* RESTRICT src, uint16* RESTRICT clut);
static void WriteCLUT_T16_I4_CSM1(const uint16* RESTRICT src, uint16* RESTRICT clut);
static void ReadCLUT_T32_I8(const uint16* RESTRICT clut, uint32* RESTRICT dst);
static void ReadCLUT_T32_I4(const uint16* RESTRICT clut, uint32* RESTRICT dst);
//static void ReadCLUT_T32_I4(const uint16* RESTRICT clut, uint32* RESTRICT dst32, uint64* RESTRICT dst64);
//static void ReadCLUT_T16_I8(const uint16* RESTRICT clut, uint32* RESTRICT dst);
//static void ReadCLUT_T16_I4(const uint16* RESTRICT clut, uint32* RESTRICT dst);
//static void ReadCLUT_T16_I4(const uint16* RESTRICT clut, uint32* RESTRICT dst32, uint64* RESTRICT dst64);
static void ExpandCLUT64_T32_I8(const uint32* RESTRICT src, uint64* RESTRICT dst);
static void ExpandCLUT64_T32(const GSVector4i& hi, const GSVector4i& lo0, const GSVector4i& lo1, const GSVector4i& lo2, const GSVector4i& lo3, GSVector4i* dst);
static void ExpandCLUT64_T32(const GSVector4i& hi, const GSVector4i& lo, GSVector4i* dst);
//static void ExpandCLUT64_T16_I8(const uint32* RESTRICT src, uint64* RESTRICT dst);
static void ExpandCLUT64_T16(const GSVector4i& hi, const GSVector4i& lo0, const GSVector4i& lo1, const GSVector4i& lo2, const GSVector4i& lo3, GSVector4i* dst);
static void ExpandCLUT64_T16(const GSVector4i& hi, const GSVector4i& lo, GSVector4i* dst);
static void Expand16(const uint16* RESTRICT src, uint32* RESTRICT dst, int w, const GIFRegTEXA& TEXA);
public:
GSClut(GSLocalMemory* mem);
virtual ~GSClut();
void Invalidate();
bool WriteTest(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
void Write(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
//void Read(const GIFRegTEX0& TEX0);
void Read32(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA);
void GetAlphaMinMax32(int& amin, int& amax);
uint32 operator [] (size_t i) const {return m_buff32[i];}
operator const uint32*() const {return m_buff32;}
operator const uint64*() const {return m_buff64;}
};

View File

@ -0,0 +1,73 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSCodeBuffer.h"
GSCodeBuffer::GSCodeBuffer(size_t blocksize)
: m_blocksize(blocksize)
, m_pos(0)
, m_reserved(0)
, m_ptr(NULL)
{
}
GSCodeBuffer::~GSCodeBuffer()
{
for(list<void*>::iterator i = m_buffers.begin(); i != m_buffers.end(); i++)
{
vmfree(*i, m_blocksize);
}
}
void* GSCodeBuffer::GetBuffer(size_t size)
{
ASSERT(size < m_blocksize);
ASSERT(m_reserved == 0);
size = (size + 15) & ~15;
if(m_ptr == NULL || m_pos + size > m_blocksize)
{
m_ptr = (uint8*)vmalloc(m_blocksize, true);
m_pos = 0;
m_buffers.push_back(m_ptr);
}
uint8* ptr = &m_ptr[m_pos];
m_reserved = size;
return ptr;
}
void GSCodeBuffer::ReleaseBuffer(size_t size)
{
ASSERT(size <= m_reserved);
m_pos = ((m_pos + size) + 15) & ~15;
ASSERT(m_pos < m_blocksize);
m_reserved = 0;
}

View File

@ -0,0 +1,37 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
class GSCodeBuffer
{
list<void*> m_buffers;
size_t m_blocksize;
size_t m_pos, m_reserved;
uint8* m_ptr;
public:
GSCodeBuffer(size_t blocksize = 4096 * 64); // 256k
virtual ~GSCodeBuffer();
void* GetBuffer(size_t size);
void ReleaseBuffer(size_t size);
};

View File

@ -0,0 +1,570 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSdx.h"
#include "GSCrc.h"
CRC::Game CRC::m_games[] =
{
{0x00000000, NoTitle, NoRegion, 0},
{0x2113EA2E, MetalSlug6, JP, 0},
{0x42E05BAF, TomoyoAfter, JP, PointListPalette},
{0x7800DC84, Clannad, JP, PointListPalette},
{0xA6167B59, Lamune, JP, PointListPalette},
{0xDDB59F46, KyuuketsuKitanMoonties, JP, PointListPalette},
{0xC8EE2562, PiaCarroteYoukosoGPGakuenPrincess, JP, PointListPalette},
{0x6CF94A43, KazokuKeikakuKokoroNoKizuna, JP, PointListPalette},
{0xEDAF602D, DuelSaviorDestiny, JP, PointListPalette},
{0xA39517AB, FFX, EU, 0},
{0xA39517AE, FFX, FR, 0},
{0x941BB7D9, FFX, DE, 0},
{0xA39517A9, FFX, IT, 0},
{0x941BB7DE, FFX, ES, 0},
{0xA80F497C, FFX, ES, 0},
{0xB4414EA1, FFX, RU, 0},
{0xEE97DB5B, FFX, RU, 0},
{0xAEC495CC, FFX, RU, 0},
{0xBB3D833A, FFX, US, 0},
{0x6A4EFE60, FFX, JP, 0},
{0x3866CA7E, FFX, ASIA, 0}, // int.
{0x658597E2, FFX, JP, 0}, // int.
{0x9AAC5309, FFX2, EU, 0},
{0x9AAC530C, FFX2, FR, 0},
{0x9AAC530A, FFX2, ES, 0},
{0x9AAC530D, FFX2, DE, 0},
{0x9AAC530B, FFX2, IT, 0},
{0x48FE0C71, FFX2, US, 0},
{0x8A6D7F14, FFX2, JP, 0},
{0xE1FD9A2D, FFX2, JP, 0}, // int.
{0x11624CD6, FFX2, KO, 0},
{0x78DA0252, FFXII, EU, 0},
{0xC1274668, FFXII, EU, 0},
{0xDC2A467E, FFXII, EU, 0},
{0xCA284668, FFXII, EU, 0},
{0xC52B466E, FFXII, EU, 0}, //ES
{0xE5E71BF9, FFXII, FR, 0},
{0x280AD120, FFXII, JP, 0},
{0x08C1ED4D, HauntingGround, EU, 0},
{0x2CD5794C, HauntingGround, EU, 0},
// {0x7D4EA48F, HauntingGround, EU, 0}, // same CRC as {Genji, EU}
{0x867BB945, HauntingGround, JP, 0},
{0xE263BC4B, HauntingGround, JP, 0},
{0x901AAC09, HauntingGround, US, 0},
{0x21068223, Okami, US, 0},
{0x891F223F, Okami, EU, 0}, // PAL DE, ES & FR.
{0xC5DEFEA0, Okami, JP, 0},
{0x086273D2, MetalGearSolid3, EU, 0}, // - PAL UK & FR
{0x26A6E286, MetalGearSolid3, DE, 0},
{0x9F185CE1, MetalGearSolid3, EU, 0},
{0x98D4BC93, MetalGearSolid3, ES, 0},
{0x79ED26AD, MetalGearSolid3, EU, 0},
{0x5E31EA42, MetalGearSolid3, EU, 0},
{0xD7ED797D, MetalGearSolid3, DE, 0},
{0x053D2239, MetalGearSolid3, US, 0}, //Metal Gear Solid 3 Subsistence disc1
{0x01B2FA7F, MetalGearSolid3, US, 0}, //Metal Gear Solid 3 Subsistence disc2
{0xAA31B5BF, MetalGearSolid3, US, 0},
{0x86BC3040, MetalGearSolid3, US, 0}, //Metal Gear Solid 3 Subsistence disc1
{0x0481AD8A, MetalGearSolid3, JP, 0},
{0xC69ACB6F, MetalGearSolid3, KO, 0}, //Metal Gear Solid 3 Snake Eater
{0xB0D195EF, MetalGearSolid3, KO, 0}, //Metal Gear Solid 3 Subsistence disc1
{0x3EBABC9C, MetalGearSolid3, KO, 0}, //Metal Gear Solid 3 Subsistence disc2
{0x8A5C25A7, MetalGearSolid3, ES, 0}, //Metal Gear Solid 3 Subsistence Spanish version
{0x278722BF, DBZBT2, US, 0},
{0xFE961D28, DBZBT2, US, 0},
{0x0393B6BE, DBZBT2, EU, 0},
{0xE2F289ED, DBZBT2, JP, 0}, // Sparking Neo!
{0xE29C09A3, DBZBT2, KO, 0}, //DragonBall Z Sparking Neo
{0x0BAA4387, DBZBT2, JP, 0},
{0x35AA84D1, DBZBT2, NoRegion, 0},
{0xBE6A9CFB, DBZBT2, NoRegion, 0},
{0x428113C2, DBZBT3, US, 0},
{0xA422BB13, DBZBT3, EU, 0},
{0xCE93CB30, DBZBT3, JP, 0},
{0xF28D21F1, DBZBT3, JP, 0},
{0x983C53D2, DBZBT3, NoRegion, 0},
{0x983C53D3, DBZBT3, EU, 0},
{0x9B0E119F, DBZBT3, KO, 0}, //DragonBall Z Sparking Meteo
{0x72B3802A, SFEX3, US, 0},
{0x71521863, SFEX3, US, 0},
{0x28703748, Bully, US, 0},
{0x019CFA48, Bully, JP, 0},
{0xC78A495D, BullyCC, US, 0},
{0xC19A374E, SoTC, US, 0},
{0x7D8F539A, SoTC, EU, 0},
{0x0F0C4A9C, SoTC, EU, 0},
{0x877F3436, SoTC, JP, 0},
{0xA17D6AAA, SoTC, KO, 0},
{0x877B3D35, SoTC, CH, 0},
{0x3122B508, OnePieceGrandAdventure, US, 0},
{0x8DF14A24, OnePieceGrandAdventure, EU, 0},
{0xE446C9F9, OnePieceGrandAdventure, KO, 0},
{0xCA2073B3, OnePieceGrandBattle, KO, 0},
{0x66953267, OnePieceGrandAdventure, JP, 0},
{0xE1674F57, OnePieceGrandBattle, EU, 0},
{0x947B933B, OnePieceGrandAdventure, US, 0},
{0xB049DD5E, OnePieceGrandBattle, US, 0},
{0x5D02CC5B, OnePieceGrandBattle, NoRegion, 0},
{0x6F8545DB, ICO, US, 0},
{0xB01A4C95, ICO, JP, 0},
{0x2DF2C1EA, ICO, KO, 0},
{0x5C991F4E, ICO, EU, 0},
{0x7ACF7E03, ICO, NoRegion, 0}, // same CRC as {SpyroNewBeginning, NoRegion}
// and as "Twisted Metal - Black" (PAL).
{0x788D8B4F, ICO, EU, 0},
{0x29C28734, ICO, CH, 0},
{0xAEAD1CA3, GT4, JP, 0},
{0x30E41D93, GT4, KO, 0},
{0x44A61C8F, GT4, EU, 0},
{0x0086E35B, GT4, EU, 0},
{0x77E61C8A, GT4, US, 0},
{0x33C6E35E, GT4, US, 0},
{0x7ABDBB5E, GT3, CH, 0}, // cutie comment
{0x3E9D448A, GT3, CH, 0}, // cutie comment
{0xAD66643C, GT3, CH, 0}, // cutie comment
{0x6810C3BC, GT3, CH, 0}, //GRAN TURISMO Concept 2002 Tokyo-Geneva
{0x85AE91B3, GT3, US, 0},
{0xC220951A, GT3, JP, 0},
{0x9DE5CF65, GT3, JP, 0}, //Gran Turismo 3: A-spec
{0x60013EBD, GTConcept, EU, 0},
{0xB590CE04, GTConcept, EU, 0},
{0x0EEF32A3, GTConcept, KO, 0}, //Gran Turismo Concept 2002 Tokyo-Seoul
{0xC164550A, WildArms5, JPUNDUB, 0},
{0xC1640D2C, WildArms5, US, 0},
{0x0FCF8FE4, WildArms5, EU, 0},
{0x2294D322, WildArms5, JP, 0},
{0x565B6170, WildArms5, JP, 0},
{0xBBC3EFFA, WildArms4, US, 0},
{0xBBC396EC, WildArms4, US, 0}, //hmm such a small diff in the CRC..
{0x7B2DE9CC, WildArms4, EU, 0},
{0x8B029334, Manhunt2, EU, 0},
{0x3B0ADBEF, Manhunt2, US, 0},
{0x09F49E37, CrashBandicootWoC, NoRegion, 0},
{0x103B5706, CrashBandicootWoC, US, 0}, //American Greatest Hits release
{0x75182BE5, CrashBandicootWoC, US, 0},
{0x5188ABCA, CrashBandicootWoC, US, 0},
{0x3A03D62F, CrashBandicootWoC, EU, 0},
{0x013E349D, ResidentEvil4, US, 0},
{0xDBB7A559, ResidentEvil4, US, 0},
{0x6BA2F6B9, ResidentEvil4, EU, 0},
{0x60FA8C69, ResidentEvil4, JP, 0},
{0x5F254B7C, ResidentEvil4, KO, 0},
{0x72E1E60E, Spartan, EU, 0},
{0x26689C87, Spartan, JP, 0},
{0x08277A9E, Spartan, US, 0},
{0xA32F7CD0, AceCombat4, US, 0},
{0x5ED8FB53, AceCombat4, JP, 0},
{0x1B9B7563, AceCombat4, EU, 0},
{0xFC46EA61, Tekken5, JP, 0},
{0x1F88EE37, Tekken5, EU, 0},
{0x1F88BECD, Tekken5, EU, 0}, //language selector...
{0x652050D2, Tekken5, US, 0},
{0xEA64EF39, Tekken5, KO, 0},
{0x9E98B8AE, IkkiTousen, JP, 0},
{0xD6385328, GodOfWar, US, 0},
{0xF2A8D307, GodOfWar, US, 0},
{0xFB0E6D72, GodOfWar, EU, 0},
{0xEB001875, GodOfWar, EU, 0},
{0xCF148C74, GodOfWar, EU, 0},
{0xCA052D22, GodOfWar, JP, 0},
{0xBFCC1795, GodOfWar, KO, 0},
{0x9567B7D6, GodOfWar, KO, 0},
{0x9B5C97BA, GodOfWar, KO, 0},
{0xA61A4C6D, GodOfWar, US, 0},
{0xE23D532B, GodOfWar, NoRegion, 0},
{0xDF1AF973, GodOfWar, EU, 0},
{0x1A85E924, GodOfWar, NoRegion, 0}, // cutie comment
{0x608ACBD3, GodOfWar, CH, 0}, // cutie comment
{0x2F123FD8, GodOfWar2, US, 0}, // same CRC as RU
{0x44A8A22A, GodOfWar2, EU, 0},
{0x60BC362B, GodOfWar2, EU, 0},
{0x4340C7C6, GodOfWar2, KO, 0},
{0xE96E55BD, GodOfWar2, JP, 0},
{0xF8CD3DF6, GodOfWar2, NoRegion, 0},
{0x0B82BFF7, GodOfWar2, NoRegion, 0},
{0x5990866F, GodOfWar2, NoRegion, 0},
{0xC4C4FD5F, GodOfWar2, CH, 0},
{0xDCD9A9F7, GodOfWar2, EU, 0},
{0xFA0DF523, GodOfWar2, CH, 0}, // cutie comment
{0x9FEE3466, GodOfWar2, CH, 0}, // cutie comment
{0x5D482F18, JackieChanAdv, EU, 0},
{0xF0A6D880, HarvestMoon, US, 0},
{0x9536E111, NamcoXCapcom, JP, 0},
{0x75C01A04, NamcoXCapcom, US, 0}, // same CRC as another JP disc
{0x95CC86EF, GiTS, US, 0}, // same CRC also reported as EU
{0xA5768F53, GiTS, JP, 0},
{0xA3643EB1, GiTS, KO, 0},
{0xBF6F101F, GiTS, EU, 0}, // same CRC as another US disc
{0x6BF11378, Onimusha3, US, 0},
{0x71320CA8, Onimusha3, JP, 0},
{0xDAFFFB0D, Onimusha3, KO, 0},
{0xF442260C, MajokkoALaMode2, JP, 0},
{0x14FE77F7, TalesOfAbyss, US, 0},
{0x045D77E9, TalesOfAbyss, JPUNDUB, 0},
{0xAA5EC3A3, TalesOfAbyss, JP, 0},
{0xFB236A46, SonicUnleashed, US, 0},
{0x8C913264, SonicUnleashed, EU, 0},
{0x5C1EBD61, SimpsonsGame, EU, 0},
{0x5C1EBF61, SimpsonsGame, FR, 0},
{0x4C7BB3C8, SimpsonsGame, NoRegion, 0},
{0x4C94B32C, SimpsonsGame, NoRegion, 0},
{0x565B7E04, SimpsonsGame, IT, 0},
{0x206779D8, SimpsonsGame, EU, 0},
{0xBBE4D862, SimpsonsGame, US, 0},
{0xD71B57F4, Genji, US, 0},
{0xFADEBC45, Genji, EU, 0},
{0xB4776FC1, Genji, JP, 0},
{0x56242EC9, Genji, KO, 0},
{0xCDAF243D, Genji, CH, 0},
{0x2A5E0B61, Genji, CH, 0},
{0x7D4EA48F, Genji, EU, 0}, // same CRC as {HauntingGround, EU}
{0xE04EA200, StarOcean3, EU, 0},
{0x23A97857, StarOcean3, US, 0},
{0xBEC32D49, StarOcean3, JP, 0},
{0x8192A241, StarOcean3, JP, 0}, //NTSC JP special directors cut limited extra sugar on top edition (the special one :p)
// it's the US version with speach files from JP... {0x23A97857, StarOcean3, JPUNDUB, 0},
{0xCC96CE93, ValkyrieProfile2, US, 0},
{0x774DE8E2, ValkyrieProfile2, JP, 0},
{0x04CCB600, ValkyrieProfile2, EU, 0},
{0xB65E141B, ValkyrieProfile2, DE, 0}, // PAL German
{0xC70FC973, ValkyrieProfile2, IT, 0},
{0x47B9B2FD, RadiataStories, US, 0},
{0xAC73005E, RadiataStories, JP, 0},
{0xE8FCF8EC, SMTNocturne, US, ZWriteMustNotClear}, // saves/reloads z buffer around shadow drawing, same issue with all the SMT games following
{0xF0A31EE3, SMTNocturne, EU, ZWriteMustNotClear}, // SMTNocturne (Lucifers Call in EU)
{0xAE0DE7B7, SMTNocturne, EU, ZWriteMustNotClear}, // SMTNocturne (Lucifers Call in EU)
{0xD60DA6D4, SMTNocturne, JP, ZWriteMustNotClear}, // SMTNocturne
{0x0E762E8D, SMTNocturne, JP, ZWriteMustNotClear}, // SMTNocturne Maniacs
{0x47BA9034, SMTNocturne, JP, ZWriteMustNotClear}, // SMTNocturne Maniacs Chronicle
{0xD3FFC263, SMTNocturne, KO, ZWriteMustNotClear},
{0xD7273511, SMTDDS1, US, ZWriteMustNotClear}, // SMT Digital Devil Saga
{0x1683A6BE, SMTDDS1, EU, ZWriteMustNotClear}, // SMT Digital Devil Saga
{0x44865CE1, SMTDDS1, JP, ZWriteMustNotClear}, // SMT Digital Devil Saga
{0xF2E397C0, SMTDDS1, KO, ZWriteMustNotClear}, // SMT Digital Devil Saga
{0x43202D1A, SMTDDS2, KO, ZWriteMustNotClear}, // SMT Digital Devil Saga 2
{0xD382C164, SMTDDS2, US, ZWriteMustNotClear}, // SMT Digital Devil Saga 2
{0xD568B684, SMTDDS2, EU, ZWriteMustNotClear}, // SMT Digital Devil Saga 2
{0xE47C1A9C, SMTDDS2, JP, ZWriteMustNotClear}, // SMT Digital Devil Saga 2
{0x0B8AB37B, RozenMaidenGebetGarden, JP, 0},
{0x1CC39DBD, SuikodenTactics, US, 0},
{0x3E205556, SuikodenTactics, EU, 0},
{0xB808413B, SuikodenTactics, JP, 0},
{0x64C58FB4, TenchuFS, US, 0},
{0xE7CCCB1E, TenchuFS, EU, 0},
{0x1969B19A, TenchuFS, ES, 0}, //PAL Spanish
{0xBF0DC4CE, TenchuFS, DE, 0},
{0x696BBEC3, TenchuFS, KO, 0},
{0x525C1994, TenchuFS, ASIA, 0},
{0x0D73BBCD, TenchuFS, KO, 0},
{0xAFBFB287, TenchuWoH, KO, 0},
{0x767E383D, TenchuWoH, US, 0},
{0x83261085, TenchuWoH, DE, 0}, //PAL German
{0x7FA1510D, TenchuWoH, EU, 0}, //PAL ES, IT
{0xC8DADF58, TenchuWoH, EU, 0},
{0x13DD9957, TenchuWoH, JP, 0},
{0x8BC95883, Sly3, US, 0},
{0x8164C614, Sly3, EU, 0},
{0xA8CC1583, Sly3, KO, 0},
{0x518DD841, Sly2, KO, 0},
{0x07652DD9, Sly2, US, 0},
{0xFDA1CBF6, Sly2, EU, 0},
{0x15DD1F6F, Sly2, NoRegion, 0},
{0xA9C82AB9, DemonStone, US, 0},
{0x7C7578F3, DemonStone, EU, 0},
{0x22425C19, DemonStone, KO, 0},
{0x506644B3, BigMuthaTruckers, EU, 0},
{0x90F0D852, BigMuthaTruckers, US, 0},
{0x5CC9BF81, TimeSplitters2, EU, 0},
{0x12532F1C, TimeSplitters2, US, 0},
{0xC818BEC2, LordOfTheRingsTwoTowers, US, 0},
{0xDC43F2B8, LordOfTheRingsTwoTowers, EU, 0},
{0x9ABF90FB, LordOfTheRingsTwoTowers, ES, 0},
{0x5FF407EE, LordOfTheRingsTwoTowers, IT, 0},
{0xC0E909E9, LordOfTheRingsTwoTowers, JP, 0},
{0x6898435D, LordOfTheRingsTwoTowers, KO, 0},
{0xDC2F9B98, LordOfTheRingsTwoTowers, CH, 0}, // cutie comment
{0xEB198738, LordOfTheRingsThirdAge, US, 0},
{0x614F4CF4, LordOfTheRingsThirdAge, EU, 0},
{0x37CD4279, LordOfTheRingsThirdAge, KO, 0},
{0xE169BAF8, RedDeadRevolver, US, 0},
{0xE2E67E23, RedDeadRevolver, EU, 0},
{0xEDDD6573, SpidermanWoS, US, 0}, //Web of Shadows
{0xF14C1D82, SpidermanWoS, EU, 0},
{0xF56C7948, HeavyMetalThunder, JP, 0},
{0x2498951B, SilentHill3, US, 0},
{0x5088CCDB, SilentHill3, EU, 0},
{0x8CFE667F, SilentHill3, JP, 0},
{0xC6CBDE91, SilentHill3, KO, 0},
{0x6B149273, SilentHill2, EU, 0},
{0x6BBD4932, SilentHill2, EU, 0}, // Director's Cut
{0x8E8E384B, SilentHill2, US, 0},
{0xFE06A030, SilentHill2, US, 0}, //greatest hits
{0xE36E16C9, SilentHill2, JP, 0},
{0x380D6782, SilentHill2, JP, 0}, //Saigo no uta
{0x6DF62AEA, BleachBladeBattlers, JP, 0},
{0x6EB71AB0, BleachBladeBattlers, JP, 0}, //2nd
{0x3A446111, CastlevaniaCoD, US, 0},
{0xF321BC38, CastlevaniaCoD, EU, 0},
{0x950876FA, CastlevaniaCoD, KO, 0},
{0x237B84D3, CastlevaniaCoD, CH, 0},
{0x28270F7D, CastlevaniaLoI, US, 0},
{0x306CDADA, CastlevaniaLoI, EU, 0},
{0xA36CFF6C, CastlevaniaLoI, JP, 0},
{0x9A93FE5D, CastlevaniaLoI, KO, 0},
{0xA79B0491, NanoBreaker, JP, 0},
{0x7985D894, FinalFightStreetwise, US, 0},
{0xED4BF0D3, FinalFightStreetwise, US, 0}, // cutie comment
{0x73C560BA, FinalFightStreetwise, EU, 0},
{0xCBB87BF9, EvangelionJo, JP, 0}, // cutie comment
{0x278A91FD, CaptainTsubasa, JP, 0}, // cutie comment
{0xC5B75C7C, Oneechanbara2Special, JP, 0}, // cutie comment
{0xC0659AD1, NarutimateAccel, JP, 0}, // cutie comment
{0xF3D9DFBE, NarutimateAccel, JP, 0},
{0x59739DDE, Naruto, JP, 0}, // cutie comment
{0xF7786EE4, EternalPoison, JP, 0}, // cutie comment
{0x2BE55519, EternalPoison, US, 0},
{0xE01F57EC, LegoBatman, US, 0}, // cutie comment
{0xE01F57ED, LegoBatman, EU, 0},
{0xE0347841, XE3, JP, 0}, // cutie comment
{0xA4E88698, XE3, CH, 0},
{0x2088950A, XE3, US, 0},
// DMC(1)? {0x79B8A95F, DevilMayCry3, US, 0},
{0x7F3D692D, DevilMayCry3, CH, 0},
// {0x1A85E924, DevilMayCry3, CH, 0}, // same CRC as {GodOfWar, NoRegion}
{0xB1995E29, ShadowofRome, EU, 0}, // cutie comment
{0x958DCA28, ShadowofRome, EU, 0},
{0x57818AF6, ShadowofRome, US, 0},
{0xF21EE6E0, CrashNburn, US, 0},
{0x694A998E, TombRaiderUnderworld, JP, 0}, // cutie comment
{0x8E214549, TombRaiderUnderworld, EU, 0},
{0xB639EB17, TombRaiderAnniversary, US, 0},
{0xB05805B6, TombRaiderAnniversary, JP, 0}, // cutie comment
{0xA629A376, TombRaiderAnniversary, EU, 0},
{0xBC8B3F50, TombRaiderLegend, US, 0}, // cutie comment
{0x05177ECE, TombRaiderLegend, EU, 0},
{0x08FFF00D, SSX3, JP, 0}, // cutie comment
{0xCE942B2A, SSX3, EU, 0},
{0x5C891FF1, Black, US, 0},
{0xCAA04879, Black, EU, 0},
{0xADDFF505, Black, EU, 0}, //?
{0xB3A9F9ED, Black, JP, 0},
{0x7838882F, VF4, JP, 0},
{0xEA131B57, VF4, US, 0},
{0x4F755D39, TyTasmanianTiger, US, 0},
{0xD59D3252, TyTasmanianTiger, EU, 0},
{0x5A1BB2A1, TyTasmanianTiger2, US, 0},
{0x44A5FA15, FFVIIDoC, US, 0},
{0x33F7D21A, FFVIIDoC, EU, 0},
{0xAFAC88EF, FFVIIDoC, JP, 0},
{0x568A5C78, DigimonRumbleArena2, US, 0},
{0x785E22BB, DigimonRumbleArena2, EU, 0},
{0x4C5CE4C3, DigimonRumbleArena2, EU, 0},
{0x7F995E8D, DigimonRumbleArena2, JP, 0},
{0x115A184D, DigimonRumbleArena2, KO, 0},
{0x879CDA5E, StarWarsForceUnleashed, US, 0},
{0x137C792E, StarWarsForceUnleashed, US, 0},
{0x503BF9E1, StarWarsBattlefront, NoRegion, 0}, // EU and US versions have the same CRC
{0x02F4B541, StarWarsBattlefront2, NoRegion, 0}, // EU and US versions have the same CRC
{0xA8DB29DF, BlackHawkDown, EU, 0},
{0x25FC361B, DevilMayCry3, US, 0}, //SE
{0x2F7D8AD5, DevilMayCry3, US, 0},
{0x0BED0AF9, DevilMayCry3, US, 0},
{0x18C9343F, DevilMayCry3, EU, 0}, //SE
{0x7ADCB24A, DevilMayCry3, EU, 0},
{0x79C952B0, DevilMayCry3, JP, 0}, //SE
{0x7F3DDEAB, DevilMayCry3, JP, 0},
{0x05931990, DevilMayCry3, KO, 0},
{0x4AD36D59, DevilMayCry3, RU, 0},
{0xBEBF8793, BurnoutTakedown, US, 0},
{0x75BECC18, BurnoutTakedown, EU, 0},
{0xCE49B0DE, BurnoutTakedown, EU, 0},
{0xD224D348, BurnoutRevenge, US, 0},
{0x7E83CC5B, BurnoutRevenge, EU, 0},
{0xEEA60511, BurnoutRevenge, KO, 0},
{0x8C9576A1, BurnoutDominator, US, 0},
{0x8C9576B4, BurnoutDominator, EU, 0},
{0x4A0E5B3A, MidnightClub3, US, 0}, //dub
{0xEBE1972D, MidnightClub3, EU, 0}, //dub
{0x60A42FF5, MidnightClub3, US, 0}, //remix
{0x4B1A0FFA, XmenOriginsWolverine, US, 0},
{0xBFF3DBCB, CallofDutyFinalFronts, US, 0},
{0xB78A5F5A, CallofDutyFinalFronts, EU, 0},
{0xD03D4C77, SpyroNewBeginning, US, 0},
{0x0EE5646B, SpyroNewBeginning, EU, 0},
// {0x7ACF7E03, SpyroNewBeginning, NoRegion, 0}, // same CRC as {ICO, NoRegion}
// and as "Twisted Metal - Black" (PAL).
{0xB80CE8EC, SpyroEternalNight, US, 0},
{0x8AE9536D, SpyroEternalNight, EU, 0},
{0xC95F0198, SpyroEternalNight, NoRegion, 0},
{0x43AB7214, TalesOfLegendia, US, 0},
{0x1F8640E0, TalesOfLegendia, JP, 0},
{0xE4F5DA2B, TalesOfLegendia, KO, 0},
{0x98C7B76D, NanoBreaker, US, 0},
{0x7098BE76, NanoBreaker, KO, 0},
{0x9B89F425, NanoBreaker, EU, 0},
{0x519E816B, Kunoichi, US, 0}, //Nightshade
{0x3FB419FD, Kunoichi, JP, 0},
{0x086D198E, Kunoichi, CH, 0},
{0x3B470BBD, Kunoichi, EU, 0},
{0x6BA65DD8, Kunoichi, KO, 0},
{0XD3F182A3, Yakuza, EU, 0},
{0x6F9F99F8, Yakuza, EU, 0},
{0x388F687B, Yakuza, US, 0},
{0xB7B3800A, Yakuza, JP, 0},
{0xA60C2E65, Yakuza2, EU, 0},
{0x800E3E5A, Yakuza2, EU, 0},
{0x97E9C87E, Yakuza2, US, 0},
{0xC6B95C48, Yakuza2, JP, 0},
{0x9000252A, SkyGunner, JP, 0},
{0x93092623, SkyGunner, JP, 0},
{0xA9461CB2, SkyGunner, US, 0},
{0xB799A60C, SkyGunner, NoRegion, 0},
{0x6848699B, JamesBondEverythingOrNothing, US, 0},
{0x5FFFDE40, JamesBondEverythingOrNothing, EU, 0},
{0xF7FB054C, Siren, CH, 0}, // cutie comment
{0x47C2C34A, Siren, KO, 0},
{0xB083CCC2, Siren, EU, 0}, // Spanish
{0x90F4B057, ZettaiZetsumeiToshi2, CH, 0},
{0xC988ECBB, ZettaiZetsumeiToshi2, JP, 0},
{0x2905C5C6, ZettaiZetsumeiToshi2, US, 0}, // Raw Danger!
{0x81CA29BE, VF4EVO, EU, 0},
{0xC9DEF513, VF4EVO, US, 0},
{0x7B402694, VF4EVO, KO, 0},
{0xAB01411F, VF4EVO, JP, 0},
{0xE11DFA28, Dororo, CH, 0},
{0x89954774, Dororo, US, 0},
{0xFDA2F2DF, Dororo, KO, 0},
{0xBD17248E, ShinOnimusha, JP, 0},
{0xBE17248E, ShinOnimusha, JP, 0},
{0xB817248E, ShinOnimusha, JP, 0},
{0x812C5A96, ShinOnimusha, EU, 0},
{0xFE44479E, ShinOnimusha, US, 0},
{0xFFDE85E9, ShinOnimusha, US, 0},
{0xE21404E2, GetaWay, US, 0},
{0xE78971DF, GetaWayBlackMonday, US, 0},
{0x1130BF23, SakuraTaisen, CH, 0}, // cutie comment
{0x4FAE8B83, SakuraTaisen, KO, 0},
{0xEF06DBD6, SakuraWarsSoLongMyLove, JP, 0}, // cutie comment
{0xDD41054D, SakuraWarsSoLongMyLove, US, 0}, // cutie comment
{0xC2E3A7A4, SakuraWarsSoLongMyLove, KO, 0},
{0x4A4B623A, FightingBeautyWulong, JP,0}, // cutie comment
{0x5AC7E79C, TouristTrophy, CH, 0}, // cutie comment
{0xFF9C0E93, TouristTrophy, US, 0},
{0xCA9AA903, TouristTrophy, EU, 0}, //crc hack not fully working on PAL, still needs brightness =0
{0xA1B3F232, GTASanAndreas, EU, 0}, // cutie comment
{0x399A49CA, GTASanAndreas, US, 0},
{0x60FE139C, GTASanAndreas, JP, 0},
{0x2615F542, FrontMission5, JP, 0},
{0xF60255AC, FrontMission5, JP, 0},
{0xCB783836, FrontMission5, JP, 0},
{0xAEDAEE99, GodHand, JP, 0},
{0x6FB69282, GodHand, US, 0},
{0x924C4AA6, GodHand, KO, 0},
{0x9637D496, KnightsOfTheTemple2, JP, 0}, // cutie comment
{0x4E811100, UltramanFightingEvolution, JP, 0}, // cutie comment
{0xF7F181C3, DeathByDegreesTekkenNinaWilliams, CH, 0}, // cutie comment
{0xF088FA5B, DeathByDegreesTekkenNinaWilliams, KO, 0},
{0x59683BB0, DeathByDegreesTekkenNinaWilliams, EU, 0},
{0x771C3B47, AlpineRacer3, JP, 0}, // cutie comment
{0x7367D841, AlpineRacer3, EU, 0},
{0x449E1F6B, HummerBadlands, US, 0},
{0xAEA1B3AD, SengokuBasara, JP, 0},
{0x5B659BED, Grandia3, JP, 0},
{0x5B657DAD, Grandia3, US, 0},
{0x830B6FB1, TalesofSymphonia, JP, 0},
{0x8409FD51, TalesofDestiny, JP, 0}, // cutie comment
{0xA90CD846, TalesofDestiny, JP, 0},
{0xC4D0FACC, SDGundamGGeneration, JP, 0}, // cutie comment
{0xBBDE6926, SDGundamGGeneration, JP, 0}, // cutie comment
{0x49D60A00, SDGundamGGeneration, JP, 0}, //NEO
{0x83AFB38A, SoulCalibur2, KO, 0},
{0xE1B01308, SoulCalibur2, US, 0},
{0xFB8554A0, SoulCalibur3, JP, 0},
{0x027C604C, SoulCalibur3, US, 0},
{0x24090A12, SoulCalibur3, EU, 0},
{0x37B99B14, SoulCalibur3, KO, 0},
{0xBC5480A3, SoulCalibur3, EU, 0},
{0xFC0F8A5B, Simple2000Vol114, JP, 0},
{0x0098F740, SeintoSeiya, NoRegion, 0}, // cutie comment
{0xBDD9BAAD, UrbanReign, US, 0}, // cutie comment
{0xAE4BEBD3, UrbanReign, EU, 0},
{0x48AC09BC, SteambotChronicles, EU, 0},
{0x9F391882, SteambotChronicles, US, 0},
{0xFEFCF9DE, SteambotChronicles, JP, 0}, // Ponkotsu Roman Daikatsugeki: Bumpy Trot
{0XE1BF5DCA, SuperManReturns, US, 0},
{0x06A7506A, SacredBlaze, JP, 0},
};
hash_map<uint32, CRC::Game*> CRC::m_map;
string ToLower( string str )
{
transform( str.begin(), str.end(), str.begin(), ::tolower);
return str;
}
// The exclusions list is a comma separated list of: the word "all" and/or CRCs in standard hex notation (0x and 8 digits with leading 0's if required).
// The list is case insensitive and order insensitive.
// E.g. Disable all CRC hacks: CrcHacksExclusions=all
// E.g. Disable hacks for these CRCs: CrcHacksExclusions=0x0F0C4A9C, 0x0EE5646B, 0x7ACF7E03
bool IsCrcExcluded(string exclusionList, uint32 crc)
{
string target = format( "0x%08x", crc );
exclusionList = ToLower( exclusionList );
return ( exclusionList.find( target ) != string::npos || exclusionList.find( "all" ) != string::npos );
}
CRC::Game CRC::Lookup(uint32 crc)
{
if(m_map.empty())
{
string exclusions = theApp.GetConfig( "CrcHacksExclusions", "" );
if (exclusions.length() != 0)
printf( "GSdx: CrcHacksExclusions: %s\n", exclusions.c_str() );
int crcDups = 0;
for(size_t i = 0; i < countof(m_games); i++)
{
if( !IsCrcExcluded( exclusions, m_games[i].crc ) ){
if(m_map[m_games[i].crc]){
printf("[FIXME] GSdx: Duplicate CRC: 0x%x: (game-id/region-id) %d/%d overrides %d/%d\n"
, m_games[i].crc, m_games[i].title, m_games[i].region, m_map[m_games[i].crc]->title, m_map[m_games[i].crc]->region);
crcDups++;
}
m_map[m_games[i].crc] = &m_games[i];
}
//else
// printf( "GSdx: excluding CRC hack for 0x%08x\n", m_games[i].crc );
}
if(crcDups)
printf("[FIXME] GSdx: Duplicate CRC: Overall: %d\n", crcDups);
}
hash_map<uint32, Game*>::iterator i = m_map.find(crc);
if(i != m_map.end())
{
return *i->second;
}
return m_games[0];
}

217
plugins/GSdx_legacy/GSCrc.h Normal file
View File

@ -0,0 +1,217 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
class CRC
{
public:
enum Title
{
NoTitle,
MetalSlug6,
TomoyoAfter,
Clannad,
Lamune,
KyuuketsuKitanMoonties,
PiaCarroteYoukosoGPGakuenPrincess,
KazokuKeikakuKokoroNoKizuna,
DuelSaviorDestiny,
FFX,
FFX2,
FFXII,
HauntingGround,
ShadowHearts,
Okami,
MetalGearSolid3,
DBZBT2,
DBZBT3,
SFEX3,
Bully,
BullyCC,
SoTC,
OnePieceGrandAdventure,
OnePieceGrandBattle,
ICO,
GT4,
GT3,
GTConcept,
WildArms5,
WildArms4,
Manhunt2,
CrashBandicootWoC,
ResidentEvil4,
Spartan,
AceCombat4,
Tekken5,
IkkiTousen,
GodOfWar,
GodOfWar2,
JackieChanAdv,
HarvestMoon,
NamcoXCapcom,
GiTS,
Onimusha3,
MajokkoALaMode2,
TalesOfAbyss,
SonicUnleashed,
SimpsonsGame,
Genji,
StarOcean3,
ValkyrieProfile2,
RadiataStories,
SMTNocturne,
SMTDDS1,
SMTDDS2,
RozenMaidenGebetGarden,
EvangelionJo,
SuikodenTactics,
CaptainTsubasa,
Oneechanbara2Special,
NarutimateAccel,
Naruto,
EternalPoison,
LegoBatman,
XE3,
TenchuWoH,
TenchuFS,
Sly3,
Sly2,
ShadowofRome,
DemonStone,
BigMuthaTruckers,
TimeSplitters2,
LordOfTheRingsTwoTowers,
LordOfTheRingsThirdAge,
RedDeadRevolver,
SpidermanWoS,
HeavyMetalThunder,
SilentHill3,
SilentHill2,
BleachBladeBattlers,
CastlevaniaCoD,
CastlevaniaLoI,
FinalFightStreetwise,
CrashNburn,
TombRaiderUnderworld,
TombRaiderAnniversary,
TombRaiderLegend,
SSX3,
Black,
VF4,
TyTasmanianTiger,
TyTasmanianTiger2,
FFVIIDoC,
DigimonRumbleArena2,
StarWarsForceUnleashed,
StarWarsBattlefront,
StarWarsBattlefront2,
BlackHawkDown,
DevilMayCry3,
BurnoutTakedown,
BurnoutRevenge,
BurnoutDominator,
MidnightClub3,
XmenOriginsWolverine,
CallofDutyFinalFronts,
SpyroNewBeginning,
SpyroEternalNight,
TalesOfLegendia,
NanoBreaker,
Kunoichi,
Yakuza,
Yakuza2,
SkyGunner,
JamesBondEverythingOrNothing,
Siren,
ZettaiZetsumeiToshi2,
VF4EVO,
Dororo,
ShinOnimusha,
GetaWay,
GetaWayBlackMonday,
SakuraTaisen,
SakuraWarsSoLongMyLove,
FightingBeautyWulong,
TouristTrophy,
GTASanAndreas,
FrontMission5,
GodHand,
KnightsOfTheTemple2,
UltramanFightingEvolution,
DeathByDegreesTekkenNinaWilliams,
AlpineRacer3,
HummerBadlands,
SengokuBasara,
Grandia3,
TalesofSymphonia,
TalesofDestiny,
SDGundamGGeneration,
SoulCalibur2,
SoulCalibur3,
Simple2000Vol114,
SeintoSeiya,
UrbanReign,
SteambotChronicles,
SacredBlaze,
SuperManReturns,
TitleCount,
};
enum Region
{
NoRegion,
US,
EU,
JP,
JPUNDUB,
RU,
FR,
DE,
IT,
ES,
CH,
ASIA,
KO,
RegionCount,
};
enum Flags
{
PointListPalette = 1,
ZWriteMustNotClear = 2,
};
struct Game
{
uint32 crc;
Title title;
Region region;
uint32 flags;
};
private:
static Game m_games[];
static hash_map<uint32, Game*> m_map;
public:
static Game Lookup(uint32 crc);
};

View File

@ -0,0 +1,450 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSdx.h"
#include "GSDevice.h"
GSDevice::GSDevice()
: m_wnd(NULL)
, m_vsync(false)
, m_rbswapped(false)
, m_backbuffer(NULL)
, m_merge(NULL)
, m_weavebob(NULL)
, m_blend(NULL)
, m_shaderfx(NULL)
, m_fxaa(NULL)
, m_shadeboost(NULL)
, m_1x1(NULL)
, m_current(NULL)
, m_frame(0)
{
memset(&m_vertex, 0, sizeof(m_vertex));
memset(&m_index, 0, sizeof(m_index));
}
GSDevice::~GSDevice()
{
for_each(m_pool.begin(), m_pool.end(), delete_object());
delete m_backbuffer;
delete m_merge;
delete m_weavebob;
delete m_blend;
delete m_shaderfx;
delete m_fxaa;
delete m_shadeboost;
delete m_1x1;
}
bool GSDevice::Create(GSWnd* wnd)
{
m_wnd = wnd;
return true;
}
bool GSDevice::Reset(int w, int h)
{
for_each(m_pool.begin(), m_pool.end(), delete_object());
m_pool.clear();
delete m_backbuffer;
delete m_merge;
delete m_weavebob;
delete m_blend;
delete m_shaderfx;
delete m_fxaa;
delete m_shadeboost;
delete m_1x1;
m_backbuffer = NULL;
m_merge = NULL;
m_weavebob = NULL;
m_blend = NULL;
m_shaderfx = NULL;
m_fxaa = NULL;
m_shadeboost = NULL;
m_1x1 = NULL;
m_current = NULL; // current is special, points to other textures, no need to delete
return m_wnd != NULL;
}
void GSDevice::Present(const GSVector4i& r, int shader)
{
GSVector4i cr = m_wnd->GetClientRect();
int w = std::max<int>(cr.width(), 1);
int h = std::max<int>(cr.height(), 1);
if(!m_backbuffer || m_backbuffer->GetWidth() != w || m_backbuffer->GetHeight() != h)
{
if(!Reset(w, h))
{
return;
}
}
GL_PUSH("Present");
ClearRenderTarget(m_backbuffer, 0);
if(m_current)
{
static int s_shader[5] = {ShaderConvert_COPY, ShaderConvert_SCANLINE,
ShaderConvert_DIAGONAL_FILTER, ShaderConvert_TRIANGULAR_FILTER,
ShaderConvert_COMPLEX_FILTER}; // FIXME
Present(m_current, m_backbuffer, GSVector4(r), s_shader[shader]);
}
Flip();
GL_POP();
}
void GSDevice::Present(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, int shader)
{
StretchRect(sTex, dTex, dRect, shader);
}
GSTexture* GSDevice::FetchSurface(int type, int w, int h, bool msaa, int format)
{
GSVector2i size(w, h);
for(list<GSTexture*>::iterator i = m_pool.begin(); i != m_pool.end(); i++)
{
GSTexture* t = *i;
if(t->GetType() == type && t->GetFormat() == format && t->GetSize() == size && t->IsMSAA() == msaa)
{
m_pool.erase(i);
return t;
}
}
return CreateSurface(type, w, h, msaa, format);
}
void GSDevice::PrintMemoryUsage()
{
#ifdef ENABLE_OGL_DEBUG
uint32 pool = 0;
for(list<GSTexture*>::iterator i = m_pool.begin(); i != m_pool.end(); i++)
{
GSTexture* t = *i;
if (t)
pool += t->GetMemUsage();
}
GL_PERF("MEM: Surface Pool %dMB", pool >> 20u);
#endif
}
void GSDevice::EndScene()
{
m_vertex.start += m_vertex.count;
m_vertex.count = 0;
m_index.start += m_index.count;
m_index.count = 0;
}
void GSDevice::Recycle(GSTexture* t)
{
if(t)
{
// FIXME: WARNING: Broken Texture Cache reuse render target without any
// cleaning (or uploading of correct gs mem data) Ofc it is wrong. If
// blending is enabled, rendering would be completely broken. However
// du to wrong invalidation of the TC it is sometimes better to reuse
// (partially) wrong data...
//
// Invalidating the data might be even worse. I'm not sure invalidating data really
// help on the perf. But people reports better perf on BDG2 (memory intensive) on OpenGL.
// It could be the reason.
t->Invalidate();
t->last_frame_used = m_frame;
m_pool.push_front(t);
//printf("%d\n",m_pool.size());
while(m_pool.size() > 300)
{
delete m_pool.back();
m_pool.pop_back();
}
}
}
void GSDevice::AgePool()
{
m_frame++;
while(m_pool.size() > 20 && m_frame - m_pool.back()->last_frame_used > 10)
{
delete m_pool.back();
m_pool.pop_back();
}
}
GSTexture* GSDevice::CreateRenderTarget(int w, int h, bool msaa, int format)
{
return FetchSurface(GSTexture::RenderTarget, w, h, msaa, format);
}
GSTexture* GSDevice::CreateDepthStencil(int w, int h, bool msaa, int format)
{
return FetchSurface(GSTexture::DepthStencil, w, h, msaa, format);
}
GSTexture* GSDevice::CreateTexture(int w, int h, int format)
{
return FetchSurface(GSTexture::Texture, w, h, false, format);
}
GSTexture* GSDevice::CreateOffscreen(int w, int h, int format)
{
return FetchSurface(GSTexture::Offscreen, w, h, false, format);
}
void GSDevice::StretchRect(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, int shader, bool linear)
{
StretchRect(sTex, GSVector4(0, 0, 1, 1), dTex, dRect, shader, linear);
}
GSTexture* GSDevice::GetCurrent()
{
return m_current;
}
void GSDevice::Merge(GSTexture* sTex[2], GSVector4* sRect, GSVector4* dRect, const GSVector2i& fs, bool slbg, bool mmod, const GSVector4& c)
{
if(m_merge == NULL || m_merge->GetSize() != fs)
{
Recycle(m_merge);
m_merge = CreateRenderTarget(fs.x, fs.y, false);
}
// TODO: m_1x1
// KH:COM crashes at startup when booting *through the bios* due to m_merge being NULL.
// (texture appears to be non-null, and is being re-created at a size around like 1700x340,
// dunno if that's relevant) -- air
if(m_merge)
{
GSTexture* tex[2] = {NULL, NULL};
for(size_t i = 0; i < countof(tex); i++)
{
if(sTex[i] != NULL)
{
tex[i] = sTex[i]->IsMSAA() ? Resolve(sTex[i]) : sTex[i];
}
}
DoMerge(tex, sRect, m_merge, dRect, slbg, mmod, c);
for(size_t i = 0; i < countof(tex); i++)
{
if(tex[i] != sTex[i])
{
Recycle(tex[i]);
}
}
}
else
{
printf("GSdx: m_merge is NULL!\n");
}
m_current = m_merge;
}
void GSDevice::Interlace(const GSVector2i& ds, int field, int mode, float yoffset)
{
if(m_weavebob == NULL || m_weavebob->GetSize() != ds)
{
delete m_weavebob;
m_weavebob = CreateRenderTarget(ds.x, ds.y, false);
}
if(mode == 0 || mode == 2) // weave or blend
{
// weave first
DoInterlace(m_merge, m_weavebob, field, false, 0);
if(mode == 2)
{
// blend
if(m_blend == NULL || m_blend->GetSize() != ds)
{
delete m_blend;
m_blend = CreateRenderTarget(ds.x, ds.y, false);
}
DoInterlace(m_weavebob, m_blend, 2, false, 0);
m_current = m_blend;
}
else
{
m_current = m_weavebob;
}
}
else if(mode == 1) // bob
{
DoInterlace(m_merge, m_weavebob, 3, true, yoffset * field);
m_current = m_weavebob;
}
else
{
m_current = m_merge;
}
}
void GSDevice::ExternalFX()
{
GSVector2i s = m_current->GetSize();
if (m_shaderfx == NULL || m_shaderfx->GetSize() != s)
{
delete m_shaderfx;
m_shaderfx = CreateRenderTarget(s.x, s.y, false);
}
if (m_shaderfx != NULL)
{
GSVector4 sRect(0, 0, 1, 1);
GSVector4 dRect(0, 0, s.x, s.y);
StretchRect(m_current, sRect, m_shaderfx, dRect, 7, false);
DoExternalFX(m_shaderfx, m_current);
}
}
void GSDevice::FXAA()
{
GSVector2i s = m_current->GetSize();
if(m_fxaa == NULL || m_fxaa->GetSize() != s)
{
delete m_fxaa;
m_fxaa = CreateRenderTarget(s.x, s.y, false);
}
if(m_fxaa != NULL)
{
GSVector4 sRect(0, 0, 1, 1);
GSVector4 dRect(0, 0, s.x, s.y);
StretchRect(m_current, sRect, m_fxaa, dRect, 7, false);
DoFXAA(m_fxaa, m_current);
}
}
void GSDevice::ShadeBoost()
{
GSVector2i s = m_current->GetSize();
if(m_shadeboost == NULL || m_shadeboost->GetSize() != s)
{
delete m_shadeboost;
m_shadeboost = CreateRenderTarget(s.x, s.y, false);
}
if(m_shadeboost != NULL)
{
GSVector4 sRect(0, 0, 1, 1);
GSVector4 dRect(0, 0, s.x, s.y);
StretchRect(m_current, sRect, m_shadeboost, dRect, 0, false);
DoShadeBoost(m_shadeboost, m_current);
}
}
bool GSDevice::ResizeTexture(GSTexture** t, int w, int h)
{
if(t == NULL) {ASSERT(0); return false;}
GSTexture* t2 = *t;
if(t2 == NULL || t2->GetWidth() != w || t2->GetHeight() != h)
{
delete t2;
t2 = CreateTexture(w, h);
*t = t2;
}
return t2 != NULL;
}
GSAdapter::operator std::string() const
{
char buf[sizeof "12345678:12345678:12345678:12345678"];
sprintf(buf, "%.4X:%.4X:%.8X:%.2X", vendor, device, subsys, rev);
return buf;
}
bool GSAdapter::operator==(const GSAdapter &desc_dxgi) const
{
return vendor == desc_dxgi.vendor
&& device == desc_dxgi.device
&& subsys == desc_dxgi.subsys
&& rev == desc_dxgi.rev;
}
#ifdef _WIN32
GSAdapter::GSAdapter(const DXGI_ADAPTER_DESC1 &desc_dxgi)
: vendor(desc_dxgi.VendorId)
, device(desc_dxgi.DeviceId)
, subsys(desc_dxgi.SubSysId)
, rev(desc_dxgi.Revision)
{
}
GSAdapter::GSAdapter(const D3DADAPTER_IDENTIFIER9 &desc_d3d9)
: vendor(desc_d3d9.VendorId)
, device(desc_d3d9.DeviceId)
, subsys(desc_d3d9.SubSysId)
, rev(desc_d3d9.Revision)
{
}
#endif
#ifdef __linux__
// TODO
#endif

View File

@ -0,0 +1,226 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSWnd.h"
#include "GSTexture.h"
#include "GSVertex.h"
#include "GSAlignedClass.h"
enum ShaderConvert {
ShaderConvert_COPY = 0,
ShaderConvert_RGBA8_TO_16_BITS,
ShaderConvert_DATM_1,
ShaderConvert_DATM_0,
ShaderConvert_MOD_256,
ShaderConvert_SCANLINE = 5,
ShaderConvert_DIAGONAL_FILTER,
ShaderConvert_TRANSPARENCY_FILTER,
ShaderConvert_TRIANGULAR_FILTER,
ShaderConvert_COMPLEX_FILTER,
ShaderConvert_FLOAT32_TO_32_BITS = 10,
ShaderConvert_FLOAT32_TO_RGBA8,
ShaderConvert_FLOAT16_TO_RGB5A1,
ShaderConvert_RGBA8_TO_FLOAT32 = 13,
ShaderConvert_RGBA8_TO_FLOAT24,
ShaderConvert_RGBA8_TO_FLOAT16,
ShaderConvert_RGB5A1_TO_FLOAT16,
ShaderConvert_RGBA_TO_8I = 17
};
#pragma pack(push, 1)
class ConvertConstantBuffer
{
public:
GSVector4i ScalingFactor;
ConvertConstantBuffer() {memset(this, 0, sizeof(*this));}
};
class MergeConstantBuffer
{
public:
GSVector4 BGColor;
MergeConstantBuffer() {memset(this, 0, sizeof(*this));}
};
class InterlaceConstantBuffer
{
public:
GSVector2 ZrH;
float hH;
float _pad[1];
InterlaceConstantBuffer() {memset(this, 0, sizeof(*this));}
};
class ExternalFXConstantBuffer
{
public:
GSVector2 xyFrame;
GSVector4 rcpFrame;
GSVector4 rcpFrameOpt;
ExternalFXConstantBuffer() { memset(this, 0, sizeof(*this)); }
};
class FXAAConstantBuffer
{
public:
GSVector4 rcpFrame;
GSVector4 rcpFrameOpt;
FXAAConstantBuffer() {memset(this, 0, sizeof(*this));}
};
class ShadeBoostConstantBuffer
{
public:
GSVector4 rcpFrame;
GSVector4 rcpFrameOpt;
ShadeBoostConstantBuffer() {memset(this, 0, sizeof(*this));}
};
#pragma pack(pop)
class GSDevice : public GSAlignedClass<32>
{
list<GSTexture*> m_pool;
protected:
GSWnd* m_wnd;
bool m_vsync;
bool m_rbswapped;
GSTexture* m_backbuffer;
GSTexture* m_merge;
GSTexture* m_weavebob;
GSTexture* m_blend;
GSTexture* m_shaderfx;
GSTexture* m_fxaa;
GSTexture* m_shadeboost;
GSTexture* m_1x1;
GSTexture* m_current;
struct {size_t stride, start, count, limit;} m_vertex;
struct {size_t start, count, limit;} m_index;
unsigned int m_frame; // for ageing the pool
virtual GSTexture* CreateSurface(int type, int w, int h, bool msaa, int format) = 0;
virtual GSTexture* FetchSurface(int type, int w, int h, bool msaa, int format);
virtual void DoMerge(GSTexture* sTex[2], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, bool slbg, bool mmod, const GSVector4& c) = 0;
virtual void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset) = 0;
virtual void DoFXAA(GSTexture* sTex, GSTexture* dTex) {}
virtual void DoShadeBoost(GSTexture* sTex, GSTexture* dTex) {}
virtual void DoExternalFX(GSTexture* sTex, GSTexture* dTex) {}
public:
GSDevice();
virtual ~GSDevice();
void Recycle(GSTexture* t);
enum {Windowed, Fullscreen, DontCare};
virtual bool Create(GSWnd* wnd);
virtual bool Reset(int w, int h);
virtual bool IsLost(bool update = false) {return false;}
virtual void Present(const GSVector4i& r, int shader);
virtual void Present(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, int shader = 0);
virtual void Flip() {}
virtual void SetVSync(bool enable) {m_vsync = enable;}
virtual void BeginScene() {}
virtual void DrawPrimitive() {};
virtual void DrawIndexedPrimitive() {}
virtual void DrawIndexedPrimitive(int offset, int count) {}
virtual void EndScene();
virtual void ClearRenderTarget(GSTexture* t, const GSVector4& c) {}
virtual void ClearRenderTarget(GSTexture* t, uint32 c) {}
virtual void ClearDepth(GSTexture* t, float c) {}
virtual void ClearStencil(GSTexture* t, uint8 c) {}
virtual GSTexture* CreateRenderTarget(int w, int h, bool msaa, int format = 0);
virtual GSTexture* CreateDepthStencil(int w, int h, bool msaa, int format = 0);
virtual GSTexture* CreateTexture(int w, int h, int format = 0);
virtual GSTexture* CreateOffscreen(int w, int h, int format = 0);
virtual GSTexture* Resolve(GSTexture* t) {return NULL;}
virtual GSTexture* CopyOffscreen(GSTexture* src, const GSVector4& sRect, int w, int h, int format = 0, int ps_shader = 0) {return NULL;}
virtual void CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r) {}
virtual void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, int shader = 0, bool linear = true) {}
void StretchRect(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, int shader = 0, bool linear = true);
virtual void PSSetShaderResources(GSTexture* sr0, GSTexture* sr1) {}
virtual void PSSetShaderResource(int i, GSTexture* sRect) {}
virtual void OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i* scissor = NULL) {}
GSTexture* GetCurrent();
void Merge(GSTexture* sTex[2], GSVector4* sRect, GSVector4* dRect, const GSVector2i& fs, bool slbg, bool mmod, const GSVector4& c);
void Interlace(const GSVector2i& ds, int field, int mode, float yoffset);
void FXAA();
void ShadeBoost();
void ExternalFX();
bool ResizeTexture(GSTexture** t, int w, int h);
bool IsRBSwapped() {return m_rbswapped;}
void AgePool();
virtual void PrintMemoryUsage();
};
struct GSAdapter
{
uint32 vendor;
uint32 device;
uint32 subsys;
uint32 rev;
operator std::string() const;
bool operator==(const GSAdapter&) const;
bool operator==(const std::string &s) const
{
return (std::string)*this == s;
}
bool operator==(const char *s) const
{
return (std::string)*this == s;
}
#ifdef _WIN32
GSAdapter(const DXGI_ADAPTER_DESC1 &desc_dxgi);
GSAdapter(const D3DADAPTER_IDENTIFIER9 &desc_d3d9);
#endif
#ifdef __linux__
// TODO
#endif
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,236 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSDeviceDX.h"
#include "GSTexture11.h"
struct GSVertexShader11
{
CComPtr<ID3D11VertexShader> vs;
CComPtr<ID3D11InputLayout> il;
};
class GSDevice11 : public GSDeviceDX
{
GSTexture* CreateSurface(int type, int w, int h, bool msaa, int format);
void DoMerge(GSTexture* sTex[2], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, bool slbg, bool mmod, const GSVector4& c);
void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset = 0);
void DoFXAA(GSTexture* sTex, GSTexture* dTex);
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex);
void DoExternalFX(GSTexture* sTex, GSTexture* dTex);
void InitExternalFX();
void InitFXAA(); // Bug workaround! Stack corruption? Heap corruption? No idea
//
CComPtr<ID3D11Device> m_dev;
CComPtr<ID3D11DeviceContext> m_ctx;
CComPtr<IDXGISwapChain> m_swapchain;
CComPtr<ID3D11Buffer> m_vb;
CComPtr<ID3D11Buffer> m_vb_old;
CComPtr<ID3D11Buffer> m_ib;
CComPtr<ID3D11Buffer> m_ib_old;
bool m_srv_changed, m_ss_changed;
int spritehack;
struct
{
ID3D11Buffer* vb;
size_t vb_stride;
ID3D11Buffer* ib;
ID3D11InputLayout* layout;
D3D11_PRIMITIVE_TOPOLOGY topology;
ID3D11VertexShader* vs;
ID3D11Buffer* vs_cb;
ID3D11GeometryShader* gs;
ID3D11ShaderResourceView* ps_srv[16];
ID3D11PixelShader* ps;
ID3D11Buffer* ps_cb;
ID3D11SamplerState* ps_ss[3];
ID3D11ShaderResourceView* cs_srv[16];
ID3D11ComputeShader* cs;
ID3D11Buffer* cs_cb;
GSVector2i viewport;
GSVector4i scissor;
ID3D11DepthStencilState* dss;
uint8 sref;
ID3D11BlendState* bs;
float bf;
ID3D11RenderTargetView* rtv;
ID3D11DepthStencilView* dsv;
} m_state;
public: // TODO
CComPtr<ID3D11RasterizerState> m_rs;
bool FXAA_Compiled;
bool ExShader_Compiled;
struct
{
CComPtr<ID3D11InputLayout> il;
CComPtr<ID3D11VertexShader> vs;
CComPtr<ID3D11PixelShader> ps[10];
CComPtr<ID3D11SamplerState> ln;
CComPtr<ID3D11SamplerState> pt;
CComPtr<ID3D11DepthStencilState> dss;
CComPtr<ID3D11BlendState> bs;
} m_convert;
struct
{
CComPtr<ID3D11PixelShader> ps[2];
CComPtr<ID3D11Buffer> cb;
CComPtr<ID3D11BlendState> bs;
} m_merge;
struct
{
CComPtr<ID3D11PixelShader> ps[4];
CComPtr<ID3D11Buffer> cb;
} m_interlace;
struct
{
CComPtr<ID3D11PixelShader> ps;
CComPtr<ID3D11Buffer> cb;
} m_shaderfx;
struct
{
CComPtr<ID3D11PixelShader> ps;
CComPtr<ID3D11Buffer> cb;
} m_fxaa;
struct
{
CComPtr<ID3D11PixelShader> ps;
CComPtr<ID3D11Buffer> cb;
} m_shadeboost;
struct
{
CComPtr<ID3D11DepthStencilState> dss;
CComPtr<ID3D11BlendState> bs;
} m_date;
void SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1* vertices, bool datm);
// Shaders...
hash_map<uint32, GSVertexShader11 > m_vs;
CComPtr<ID3D11Buffer> m_vs_cb;
hash_map<uint32, CComPtr<ID3D11GeometryShader> > m_gs;
hash_map<uint32, CComPtr<ID3D11PixelShader> > m_ps;
CComPtr<ID3D11Buffer> m_ps_cb;
hash_map<uint32, CComPtr<ID3D11SamplerState> > m_ps_ss;
CComPtr<ID3D11SamplerState> m_palette_ss;
CComPtr<ID3D11SamplerState> m_rt_ss;
hash_map<uint32, CComPtr<ID3D11DepthStencilState> > m_om_dss;
hash_map<uint32, CComPtr<ID3D11BlendState> > m_om_bs;
VSConstantBuffer m_vs_cb_cache;
PSConstantBuffer m_ps_cb_cache;
bool CreateTextureFX();
public:
GSDevice11();
virtual ~GSDevice11();
bool Create(GSWnd* wnd);
bool Reset(int w, int h);
void Flip();
void SetExclusive(bool isExcl);
void DrawPrimitive();
void DrawIndexedPrimitive();
void DrawIndexedPrimitive(int offset, int count);
void Dispatch(uint32 x, uint32 y, uint32 z);
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* Resolve(GSTexture* t);
GSTexture* CopyOffscreen(GSTexture* src, const GSVector4& sRect, int w, int h, int format = 0, int ps_shader = 0);
void CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r);
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, int shader = 0, bool linear = true);
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ID3D11PixelShader* ps, ID3D11Buffer* ps_cb, bool linear = true);
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ID3D11PixelShader* ps, ID3D11Buffer* ps_cb, ID3D11BlendState* bs, bool linear = true);
void IASetVertexBuffer(const void* vertex, size_t stride, size_t count);
bool IAMapVertexBuffer(void** vertex, size_t stride, size_t count);
void IAUnmapVertexBuffer();
void IASetVertexBuffer(ID3D11Buffer* vb, size_t stride);
void IASetIndexBuffer(const void* index, size_t count);
void IASetIndexBuffer(ID3D11Buffer* ib);
void IASetInputLayout(ID3D11InputLayout* layout);
void IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY topology);
void VSSetShader(ID3D11VertexShader* vs, ID3D11Buffer* vs_cb);
void GSSetShader(ID3D11GeometryShader* gs);
void PSSetShaderResources(GSTexture* sr0, GSTexture* sr1);
void PSSetShaderResource(int i, GSTexture* sr);
void PSSetShaderResourceView(int i, ID3D11ShaderResourceView* srv);
void PSSetShader(ID3D11PixelShader* ps, ID3D11Buffer* ps_cb);
void PSSetSamplerState(ID3D11SamplerState* ss0, ID3D11SamplerState* ss1, ID3D11SamplerState* ss2 = NULL);
void CSSetShaderSRV(int i, ID3D11ShaderResourceView* srv);
void CSSetShaderUAV(int i, ID3D11UnorderedAccessView* uav);
void CSSetShader(ID3D11ComputeShader* cs, ID3D11Buffer* cs_cb);
void OMSetDepthStencilState(ID3D11DepthStencilState* dss, uint8 sref);
void OMSetBlendState(ID3D11BlendState* bs, float bf);
void OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i* scissor = NULL);
void OMSetRenderTargets(const GSVector2i& rtsize, int count, ID3D11UnorderedAccessView** uav, uint32* counters, const GSVector4i* scissor = NULL);
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);
bool HasStencil() { return true; }
bool HasDepth32() { return true; }
ID3D11Device* operator->() {return m_dev;}
operator ID3D11Device*() {return m_dev;}
operator ID3D11DeviceContext*() {return m_ctx;}
void CompileShader(const char* source, size_t size, const char* fn, ID3DInclude *include, const char* entry, D3D_SHADER_MACRO* macro, ID3D11VertexShader** vs, D3D11_INPUT_ELEMENT_DESC* layout, int count, ID3D11InputLayout** il);
void CompileShader(const char* source, size_t size, const char* fn, ID3DInclude *include, const char* entry, D3D_SHADER_MACRO* macro, ID3D11GeometryShader** gs);
void CompileShader(const char* source, size_t size, const char* fn, ID3DInclude *include, const char* entry, D3D_SHADER_MACRO* macro, ID3D11GeometryShader** gs, D3D11_SO_DECLARATION_ENTRY* layout, int count);
void CompileShader(const char* source, size_t size, const char* fn, ID3DInclude *include, const char* entry, D3D_SHADER_MACRO* macro, ID3D11PixelShader** ps);
void CompileShader(const char* source, size_t size, const char* fn, ID3DInclude *include, const char* entry, D3D_SHADER_MACRO* macro, ID3D11ComputeShader** cs);
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,255 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSDeviceDX.h"
#include "GSTexture9.h"
struct Direct3DSamplerState9
{
D3DTEXTUREFILTERTYPE FilterMin[2];
D3DTEXTUREFILTERTYPE FilterMag[2];
D3DTEXTUREFILTERTYPE FilterMip[2];
D3DTEXTUREFILTERTYPE Anisotropic[2];
D3DTEXTUREADDRESS AddressU;
D3DTEXTUREADDRESS AddressV;
D3DTEXTUREADDRESS AddressW;
DWORD MaxAnisotropy;
DWORD MaxLOD;
};
struct Direct3DDepthStencilState9
{
BOOL DepthEnable;
BOOL DepthWriteMask;
D3DCMPFUNC DepthFunc;
BOOL StencilEnable;
UINT8 StencilReadMask;
UINT8 StencilWriteMask;
D3DSTENCILOP StencilFailOp;
D3DSTENCILOP StencilDepthFailOp;
D3DSTENCILOP StencilPassOp;
D3DCMPFUNC StencilFunc;
uint32 StencilRef;
};
struct Direct3DBlendState9
{
BOOL BlendEnable;
D3DBLEND SrcBlend;
D3DBLEND DestBlend;
D3DBLENDOP BlendOp;
D3DBLEND SrcBlendAlpha;
D3DBLEND DestBlendAlpha;
D3DBLENDOP BlendOpAlpha;
UINT8 RenderTargetWriteMask;
};
struct GSVertexShader9
{
CComPtr<IDirect3DVertexShader9> vs;
CComPtr<IDirect3DVertexDeclaration9> il;
};
class GSDevice9 : public GSDeviceDX
{
GSTexture* CreateSurface(int type, int w, int h, bool msaa, int format);
void DoMerge(GSTexture* sTex[2], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, bool slbg, bool mmod, const GSVector4& c);
void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset = 0);
void DoFXAA(GSTexture* sTex, GSTexture* dTex);
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex);
void DoExternalFX(GSTexture* sTex, GSTexture* dTex);
void InitExternalFX();
void InitFXAA();
//
D3DCAPS9 m_d3dcaps;
D3DPRESENT_PARAMETERS m_pp;
CComPtr<IDirect3D9> m_d3d;
CComPtr<IDirect3DDevice9> m_dev;
CComPtr<IDirect3DSwapChain9> m_swapchain;
CComPtr<IDirect3DVertexBuffer9> m_vb;
CComPtr<IDirect3DVertexBuffer9> m_vb_old;
CComPtr<IDirect3DIndexBuffer9> m_ib;
CComPtr<IDirect3DIndexBuffer9> m_ib_old;
bool m_lost;
D3DFORMAT m_depth_format;
struct
{
IDirect3DVertexBuffer9* vb;
size_t vb_stride;
IDirect3DIndexBuffer9* ib;
IDirect3DVertexDeclaration9* layout;
D3DPRIMITIVETYPE topology;
IDirect3DVertexShader9* vs;
float* vs_cb;
int vs_cb_len;
IDirect3DTexture9* ps_srvs[3];
IDirect3DPixelShader9* ps;
float* ps_cb;
int ps_cb_len;
Direct3DSamplerState9* ps_ss;
GSVector4i scissor;
Direct3DDepthStencilState9* dss;
Direct3DBlendState9* bs;
uint32 bf;
IDirect3DSurface9* rtv;
IDirect3DSurface9* dsv;
} m_state;
public: // TODO
bool FXAA_Compiled;
bool ExShader_Compiled;
struct
{
CComPtr<IDirect3DVertexDeclaration9> il;
CComPtr<IDirect3DVertexShader9> vs;
CComPtr<IDirect3DPixelShader9> ps[10];
Direct3DSamplerState9 ln;
Direct3DSamplerState9 pt;
Direct3DDepthStencilState9 dss;
Direct3DBlendState9 bs;
} m_convert;
struct
{
CComPtr<IDirect3DPixelShader9> ps[2];
Direct3DBlendState9 bs;
} m_merge;
struct
{
CComPtr<IDirect3DPixelShader9> ps[4];
} m_interlace;
struct
{
CComPtr<IDirect3DPixelShader9> ps;
} m_shaderfx;
struct
{
CComPtr<IDirect3DPixelShader9> ps;
} m_fxaa;
struct
{
CComPtr<IDirect3DPixelShader9> ps;
} m_shadeboost;
struct
{
Direct3DDepthStencilState9 dss;
Direct3DBlendState9 bs;
} m_date;
void SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1* vertices, bool datm);
// Shaders...
hash_map<uint32, GSVertexShader9 > m_vs;
hash_map<uint32, CComPtr<IDirect3DPixelShader9> > m_ps;
hash_map<uint32, Direct3DSamplerState9* > m_ps_ss;
hash_map<uint32, Direct3DDepthStencilState9* > m_om_dss;
hash_map<uint32, Direct3DBlendState9* > m_om_bs;
hash_map<uint32, GSTexture*> m_mskfix;
GSTexture* CreateMskFix(uint32 size, uint32 msk, uint32 fix);
public:
GSDevice9();
virtual ~GSDevice9();
bool Create(GSWnd* wnd);
bool Reset(int w, int h);
bool IsLost(bool update);
void Flip();
void SetVSync(bool enable);
void BeginScene();
void DrawPrimitive();
void DrawIndexedPrimitive();
void EndScene();
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* Resolve(GSTexture* t);
GSTexture* CopyOffscreen(GSTexture* src, const GSVector4& sRect, int w, int h, int format = 0, int ps_shader = 0);
void CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r);
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, int shader = 0, bool linear = true);
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len, bool linear = true);
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len, Direct3DBlendState9* bs, bool linear = true);
void IASetVertexBuffer(const void* vertex, size_t stride, size_t count);
bool IAMapVertexBuffer(void** vertex, size_t stride, size_t count);
void IAUnmapVertexBuffer();
void IASetVertexBuffer(IDirect3DVertexBuffer9* vb, size_t stride);
void IASetIndexBuffer(const void* index, size_t count);
void IASetIndexBuffer(IDirect3DIndexBuffer9* ib);
void IASetInputLayout(IDirect3DVertexDeclaration9* layout);
void IASetPrimitiveTopology(D3DPRIMITIVETYPE topology);
void VSSetShader(IDirect3DVertexShader9* vs, const float* vs_cb, int vs_cb_len);
void PSSetShaderResources(GSTexture* sr0, GSTexture* sr1);
void PSSetShaderResource(int i, GSTexture* sr);
void PSSetShader(IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len);
void PSSetSamplerState(Direct3DSamplerState9* ss);
void OMSetDepthStencilState(Direct3DDepthStencilState9* dss);
void OMSetBlendState(Direct3DBlendState9* bs, uint32 bf);
void OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i* scissor = NULL);
IDirect3DDevice9* operator->() {return m_dev;}
operator IDirect3DDevice9*() {return m_dev;}
void CompileShader(const char *source, size_t size, const char *filename, const string& entry, const D3D_SHADER_MACRO* macro, IDirect3DVertexShader9** vs, const D3DVERTEXELEMENT9* layout, int count, IDirect3DVertexDeclaration9** il);
void CompileShader(const char *source, size_t size, const char *filename, const string& entry, const D3D_SHADER_MACRO* macro, IDirect3DPixelShader9** ps);
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);
bool HasStencil() { return m_depth_format == D3DFMT_D24S8; }
bool HasDepth32() { return m_depth_format != D3DFMT_D24S8; }
static uint32 GetMaxDepth(uint32 msaaCount = 0, std::string adapter_id = "");
static void ForceValidMsaaConfig();
};

View File

@ -0,0 +1,241 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSdx.h"
#include "GSDeviceDX.h"
#include <VersionHelpers.h>
HMODULE GSDeviceDX::s_d3d_compiler_dll = nullptr;
decltype(&D3DCompile) GSDeviceDX::s_pD3DCompile = nullptr;
bool GSDeviceDX::s_old_d3d_compiler_dll;
GSDeviceDX::GSDeviceDX()
{
m_msaa = !!theApp.GetConfig("UserHacks", 0) ? theApp.GetConfig("UserHacks_MSAA", 0) : 0;
m_msaa_desc.Count = 1;
m_msaa_desc.Quality = 0;
}
GSDeviceDX::~GSDeviceDX()
{
}
bool GSDeviceDX::LoadD3DCompiler()
{
// Windows 8.1 and later come with the latest d3dcompiler_47.dll, but
// Windows 7 devs might also have the dll available for use (which will
// have to be placed in the application directory)
s_d3d_compiler_dll = LoadLibraryEx("d3dcompiler_47.dll", nullptr, LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32);
// Windows Vista and 7 can use the older version. If the previous LoadLibrary
// call fails on Windows 8.1 and later, then the user's system is likely
// broken.
if (s_d3d_compiler_dll)
{
s_old_d3d_compiler_dll = false;
}
else
{
if (!IsWindows8Point1OrGreater())
// Use LoadLibrary instead of LoadLibraryEx, some Windows 7 systems
// have issues with it.
s_d3d_compiler_dll = LoadLibrary("D3DCompiler_43.dll");
if (s_d3d_compiler_dll == nullptr)
return false;
s_old_d3d_compiler_dll = true;
}
s_pD3DCompile = reinterpret_cast<decltype(&D3DCompile)>(GetProcAddress(s_d3d_compiler_dll, "D3DCompile"));
if (s_pD3DCompile)
return true;
FreeLibrary(s_d3d_compiler_dll);
s_d3d_compiler_dll = nullptr;
return false;
}
void GSDeviceDX::FreeD3DCompiler()
{
s_pD3DCompile = nullptr;
if (s_d3d_compiler_dll)
FreeLibrary(s_d3d_compiler_dll);
s_d3d_compiler_dll = nullptr;
}
GSTexture* GSDeviceDX::FetchSurface(int type, int w, int h, bool msaa, int format)
{
if(m_msaa < 2)
{
msaa = false;
}
return __super::FetchSurface(type, w, h, msaa, format);
}
bool GSDeviceDX::SetFeatureLevel(D3D_FEATURE_LEVEL level, bool compat_mode)
{
m_shader.level = level;
switch(level)
{
case D3D_FEATURE_LEVEL_9_1:
case D3D_FEATURE_LEVEL_9_2:
m_shader.model = "0x200";
m_shader.vs = compat_mode ? "vs_4_0_level_9_1" : "vs_2_0";
m_shader.ps = compat_mode ? "ps_4_0_level_9_1" : "ps_2_0";
break;
case D3D_FEATURE_LEVEL_9_3:
m_shader.model = "0x300";
m_shader.vs = compat_mode ? "vs_4_0_level_9_3" : "vs_3_0";
m_shader.ps = compat_mode ? "ps_4_0_level_9_3" : "ps_3_0";
break;
case D3D_FEATURE_LEVEL_10_0:
m_shader.model = "0x400";
m_shader.vs = "vs_4_0";
m_shader.gs = "gs_4_0";
m_shader.ps = "ps_4_0";
m_shader.cs = "cs_4_0";
break;
case D3D_FEATURE_LEVEL_10_1:
m_shader.model = "0x401";
m_shader.vs = "vs_4_1";
m_shader.gs = "gs_4_1";
m_shader.ps = "ps_4_1";
m_shader.cs = "cs_4_1";
break;
case D3D_FEATURE_LEVEL_11_0:
m_shader.model = "0x500";
m_shader.vs = "vs_5_0";
m_shader.gs = "gs_5_0";
m_shader.ps = "ps_5_0";
m_shader.cs = "cs_5_0";
break;
default:
ASSERT(0);
return false;
}
return true;
}
// (A - B) * C + D
// A: Cs/Cd/0
// B: Cs/Cd/0
// C: As/Ad/FIX
// D: Cs/Cd/0
// bogus: 0100, 0110, 0120, 0200, 0210, 0220, 1001, 1011, 1021
// tricky: 1201, 1211, 1221
// Source.rgb = float3(1, 1, 1);
// 1201 Cd*(1 + As) => Source * Dest color + Dest * Source alpha
// 1211 Cd*(1 + Ad) => Source * Dest color + Dest * Dest alpha
// 1221 Cd*(1 + F) => Source * Dest color + Dest * Factor
const GSDeviceDX::D3D9Blend GSDeviceDX::m_blendMapD3D9[3*3*3*3] =
{
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 0000: (Cs - Cs)*As + Cs ==> Cs
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 0001: (Cs - Cs)*As + Cd ==> Cd
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 0002: (Cs - Cs)*As + 0 ==> 0
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 0010: (Cs - Cs)*Ad + Cs ==> Cs
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 0011: (Cs - Cs)*Ad + Cd ==> Cd
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 0012: (Cs - Cs)*Ad + 0 ==> 0
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 0020: (Cs - Cs)*F + Cs ==> Cs
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 0021: (Cs - Cs)*F + Cd ==> Cd
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 0022: (Cs - Cs)*F + 0 ==> 0
{1, D3DBLENDOP_SUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA}, //*0100: (Cs - Cd)*As + Cs ==> Cs*(As + 1) - Cd*As
{0, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA}, // 0101: (Cs - Cd)*As + Cd ==> Cs*As + Cd*(1 - As)
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA}, // 0102: (Cs - Cd)*As + 0 ==> Cs*As - Cd*As
{1, D3DBLENDOP_SUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_DESTALPHA}, //*0110: (Cs - Cd)*Ad + Cs ==> Cs*(Ad + 1) - Cd*Ad
{0, D3DBLENDOP_ADD, D3DBLEND_DESTALPHA, D3DBLEND_INVDESTALPHA}, // 0111: (Cs - Cd)*Ad + Cd ==> Cs*Ad + Cd*(1 - Ad)
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_DESTALPHA}, // 0112: (Cs - Cd)*Ad + 0 ==> Cs*Ad - Cd*Ad
{1, D3DBLENDOP_SUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_BLENDFACTOR}, //*0120: (Cs - Cd)*F + Cs ==> Cs*(F + 1) - Cd*F
{0, D3DBLENDOP_ADD, D3DBLEND_BLENDFACTOR, D3DBLEND_INVBLENDFACTOR}, // 0121: (Cs - Cd)*F + Cd ==> Cs*F + Cd*(1 - F)
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_BLENDFACTOR}, // 0122: (Cs - Cd)*F + 0 ==> Cs*F - Cd*F
{1, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_ZERO}, //*0200: (Cs - 0)*As + Cs ==> Cs*(As + 1)
{0, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_ONE}, // 0201: (Cs - 0)*As + Cd ==> Cs*As + Cd
{0, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_ZERO}, // 0202: (Cs - 0)*As + 0 ==> Cs*As
{1, D3DBLENDOP_ADD, D3DBLEND_DESTALPHA, D3DBLEND_ZERO}, //*0210: (Cs - 0)*Ad + Cs ==> Cs*(Ad + 1)
{0, D3DBLENDOP_ADD, D3DBLEND_DESTALPHA, D3DBLEND_ONE}, // 0211: (Cs - 0)*Ad + Cd ==> Cs*Ad + Cd
{0, D3DBLENDOP_ADD, D3DBLEND_DESTALPHA, D3DBLEND_ZERO}, // 0212: (Cs - 0)*Ad + 0 ==> Cs*Ad
{1, D3DBLENDOP_ADD, D3DBLEND_BLENDFACTOR, D3DBLEND_ZERO}, //*0220: (Cs - 0)*F + Cs ==> Cs*(F + 1)
{0, D3DBLENDOP_ADD, D3DBLEND_BLENDFACTOR, D3DBLEND_ONE}, // 0221: (Cs - 0)*F + Cd ==> Cs*F + Cd
{0, D3DBLENDOP_ADD, D3DBLEND_BLENDFACTOR, D3DBLEND_ZERO}, // 0222: (Cs - 0)*F + 0 ==> Cs*F
{0, D3DBLENDOP_ADD, D3DBLEND_INVSRCALPHA, D3DBLEND_SRCALPHA}, // 1000: (Cd - Cs)*As + Cs ==> Cd*As + Cs*(1 - As)
{1, D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA}, //*1001: (Cd - Cs)*As + Cd ==> Cd*(As + 1) - Cs*As
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA}, // 1002: (Cd - Cs)*As + 0 ==> Cd*As - Cs*As
{0, D3DBLENDOP_ADD, D3DBLEND_INVDESTALPHA, D3DBLEND_DESTALPHA}, // 1010: (Cd - Cs)*Ad + Cs ==> Cd*Ad + Cs*(1 - Ad)
{1, D3DBLENDOP_REVSUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_DESTALPHA}, //*1011: (Cd - Cs)*Ad + Cd ==> Cd*(Ad + 1) - Cs*Ad
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_DESTALPHA}, // 1012: (Cd - Cs)*Ad + 0 ==> Cd*Ad - Cs*Ad
{0, D3DBLENDOP_ADD, D3DBLEND_INVBLENDFACTOR, D3DBLEND_BLENDFACTOR}, // 1020: (Cd - Cs)*F + Cs ==> Cd*F + Cs*(1 - F)
{1, D3DBLENDOP_REVSUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_BLENDFACTOR},//*1021: (Cd - Cs)*F + Cd ==> Cd*(F + 1) - Cs*F
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_BLENDFACTOR},// 1022: (Cd - Cs)*F + 0 ==> Cd*F - Cs*F
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 1100: (Cd - Cd)*As + Cs ==> Cs
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 1101: (Cd - Cd)*As + Cd ==> Cd
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 1102: (Cd - Cd)*As + 0 ==> 0
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 1110: (Cd - Cd)*Ad + Cs ==> Cs
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 1111: (Cd - Cd)*Ad + Cd ==> Cd
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 1112: (Cd - Cd)*Ad + 0 ==> 0
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 1120: (Cd - Cd)*F + Cs ==> Cs
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 1121: (Cd - Cd)*F + Cd ==> Cd
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 1122: (Cd - Cd)*F + 0 ==> 0
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_SRCALPHA}, // 1200: (Cd - 0)*As + Cs ==> Cs + Cd*As
{2, D3DBLENDOP_ADD, D3DBLEND_DESTCOLOR, D3DBLEND_SRCALPHA}, //#1201: (Cd - 0)*As + Cd ==> Cd*(1 + As) // ffxii main menu background glow effect
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_SRCALPHA}, // 1202: (Cd - 0)*As + 0 ==> Cd*As
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_DESTALPHA}, // 1210: (Cd - 0)*Ad + Cs ==> Cs + Cd*Ad
{2, D3DBLENDOP_ADD, D3DBLEND_DESTCOLOR, D3DBLEND_DESTALPHA}, //#1211: (Cd - 0)*Ad + Cd ==> Cd*(1 + Ad)
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_DESTALPHA}, // 1212: (Cd - 0)*Ad + 0 ==> Cd*Ad
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_BLENDFACTOR}, // 1220: (Cd - 0)*F + Cs ==> Cs + Cd*F
{2, D3DBLENDOP_ADD, D3DBLEND_DESTCOLOR, D3DBLEND_BLENDFACTOR}, //#1221: (Cd - 0)*F + Cd ==> Cd*(1 + F)
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_BLENDFACTOR}, // 1222: (Cd - 0)*F + 0 ==> Cd*F
{0, D3DBLENDOP_ADD, D3DBLEND_INVSRCALPHA, D3DBLEND_ZERO}, // 2000: (0 - Cs)*As + Cs ==> Cs*(1 - As)
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_ONE}, // 2001: (0 - Cs)*As + Cd ==> Cd - Cs*As
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_ZERO}, // 2002: (0 - Cs)*As + 0 ==> 0 - Cs*As
{0, D3DBLENDOP_ADD, D3DBLEND_INVDESTALPHA, D3DBLEND_ZERO}, // 2010: (0 - Cs)*Ad + Cs ==> Cs*(1 - Ad)
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_ONE}, // 2011: (0 - Cs)*Ad + Cd ==> Cd - Cs*Ad
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_ZERO}, // 2012: (0 - Cs)*Ad + 0 ==> 0 - Cs*Ad
{0, D3DBLENDOP_ADD, D3DBLEND_INVBLENDFACTOR, D3DBLEND_ZERO}, // 2020: (0 - Cs)*F + Cs ==> Cs*(1 - F)
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_ONE}, // 2021: (0 - Cs)*F + Cd ==> Cd - Cs*F
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_ZERO}, // 2022: (0 - Cs)*F + 0 ==> 0 - Cs*F
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_SRCALPHA}, // 2100: (0 - Cd)*As + Cs ==> Cs - Cd*As
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_INVSRCALPHA}, // 2101: (0 - Cd)*As + Cd ==> Cd*(1 - As)
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_ZERO, D3DBLEND_SRCALPHA}, // 2102: (0 - Cd)*As + 0 ==> 0 - Cd*As
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_DESTALPHA}, // 2110: (0 - Cd)*Ad + Cs ==> Cs - Cd*Ad
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_INVDESTALPHA}, // 2111: (0 - Cd)*Ad + Cd ==> Cd*(1 - Ad)
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_DESTALPHA}, // 2112: (0 - Cd)*Ad + 0 ==> 0 - Cd*Ad
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_BLENDFACTOR}, // 2120: (0 - Cd)*F + Cs ==> Cs - Cd*F
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_INVBLENDFACTOR}, // 2121: (0 - Cd)*F + Cd ==> Cd*(1 - F)
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_BLENDFACTOR}, // 2122: (0 - Cd)*F + 0 ==> 0 - Cd*F
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 2200: (0 - 0)*As + Cs ==> Cs
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 2201: (0 - 0)*As + Cd ==> Cd
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 2202: (0 - 0)*As + 0 ==> 0
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 2210: (0 - 0)*Ad + Cs ==> Cs
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 2211: (0 - 0)*Ad + Cd ==> Cd
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 2212: (0 - 0)*Ad + 0 ==> 0
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 2220: (0 - 0)*F + Cs ==> Cs
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 2221: (0 - 0)*F + Cd ==> Cd
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 2222: (0 - 0)*F + 0 ==> 0
};

View File

@ -0,0 +1,331 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSVector.h"
#include "GSDevice.h"
#include "GSAlignedClass.h"
class GSDeviceDX : public GSDevice
{
public:
#pragma pack(push, 1)
__aligned(struct, 32) VSConstantBuffer
{
GSVector4 VertexScale;
GSVector4 VertexOffset;
GSVector4 TextureScale;
struct 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 key;
};
operator uint32() {return key & 0xff;}
VSSelector() : key(0) {}
};
__aligned(struct, 32) PSConstantBuffer
{
GSVector4 FogColor_AREF;
GSVector4 HalfTexel;
GSVector4 WH;
GSVector4 MinMax;
GSVector4 MinF_TA;
GSVector4i MskFix;
GSVector4 TC_OffsetHack;
struct 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 tcoffsethack:1;
uint32 point_sampler:1;
uint32 shuffle:1;
uint32 read_ba:1;
};
uint32 key;
};
operator uint32() {return key & 0xfffffff;}
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 alpha_stencil:1;
};
uint32 key;
};
operator uint32() {return key & 0x3f;}
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];
#pragma pack(pop)
protected:
struct {D3D_FEATURE_LEVEL level; string model, vs, gs, ps, cs;} m_shader;
uint32 m_msaa;
DXGI_SAMPLE_DESC m_msaa_desc;
static HMODULE s_d3d_compiler_dll;
static decltype(&D3DCompile) s_pD3DCompile;
// Older version doesn't support D3D_COMPILE_STANDARD_FILE_INCLUDE, which
// could be useful for external shaders.
static bool s_old_d3d_compiler_dll;
GSTexture* FetchSurface(int type, int w, int h, bool msaa, int format);
public:
GSDeviceDX();
virtual ~GSDeviceDX();
bool SetFeatureLevel(D3D_FEATURE_LEVEL level, bool compat_mode);
void GetFeatureLevel(D3D_FEATURE_LEVEL& level) const {level = m_shader.level;}
virtual void SetupVS(VSSelector sel, const VSConstantBuffer* cb) = 0;
virtual void SetupGS(GSSelector sel) = 0;
virtual void SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel) = 0;
virtual void SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, uint8 afix) = 0;
virtual void SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1* vertices, bool datm) = 0;
virtual bool HasStencil() = 0;
virtual bool HasDepth32() = 0;
static bool LoadD3DCompiler();
static void FreeD3DCompiler();
template<class T> void PrepareShaderMacro(vector<T>& dst, const T* src)
{
dst.clear();
while(src && src->Definition && src->Name)
{
dst.push_back(*src++);
}
T m;
m.Name = "SHADER_MODEL";
m.Definition = m_shader.model.c_str();
dst.push_back(m);
m.Name = NULL;
m.Definition = NULL;
dst.push_back(m);
}
};

View File

@ -0,0 +1,47 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSDeviceNull.h"
bool GSDeviceNull::Create(GSWnd* wnd)
{
if(!GSDevice::Create(wnd))
return false;
Reset(1, 1);
return true;
}
bool GSDeviceNull::Reset(int w, int h)
{
if(!GSDevice::Reset(w, h))
return false;
return true;
}
GSTexture* GSDeviceNull::CreateSurface(int type, int w, int h, bool msaa, int format)
{
return new GSTextureNull(type, w, h, format);
}

View File

@ -0,0 +1,41 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSDevice.h"
#include "GSTextureNull.h"
class GSDeviceNull : public GSDevice
{
private:
GSTexture* CreateSurface(int type, int w, int h, bool msaa, int format);
void DoMerge(GSTexture* sTex[2], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, bool slbg, bool mmod, const GSVector4& c) {}
void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset = 0) {}
public:
GSDeviceNull() {}
bool Create(GSWnd* wnd);
bool Reset(int w, int h);
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,551 @@
/*
* Copyright (C) 2011-2013 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSDevice.h"
#include "GSTextureOGL.h"
#include "GSdx.h"
#include "GSVertexArrayOGL.h"
#include "GSUniformBufferOGL.h"
#include "GSShaderOGL.h"
#include "GLState.h"
// A couple of flag to determine the blending behavior
#define BLEND_A_MAX (0x100) // Impossible blending uses coeff bigger than 1
#define BLEND_C_CLR (0x200) // Clear color blending (use directly the destination color as blending factor)
#define BLEND_NO_BAR (0x400) // don't require texture barrier for the blending (because the RT is not used)
#define BLEND_ACCU (0x800) // Allow to use a mix of SW and HW blending to keep the best of the 2 worlds
#ifdef ENABLE_OGL_DEBUG_MEM_BW
extern uint64 g_real_texture_upload_byte;
extern uint64 g_vertex_upload_byte;
#endif
class GSDepthStencilOGL {
bool m_depth_enable;
GLenum m_depth_func;
bool m_depth_mask;
// Note front face and back might be split but it seems they have same parameter configuration
bool m_stencil_enable;
GLenum m_stencil_func;
GLenum m_stencil_spass_dpass_op;
public:
GSDepthStencilOGL() : m_depth_enable(false)
, m_depth_func(GL_ALWAYS)
, m_depth_mask(0)
, m_stencil_enable(false)
, m_stencil_func(0)
, m_stencil_spass_dpass_op(GL_KEEP)
{
}
void EnableDepth() { m_depth_enable = true; }
void EnableStencil() { m_stencil_enable = true; }
void SetDepth(GLenum func, bool mask) { m_depth_func = func; m_depth_mask = mask; }
void SetStencil(GLenum func, GLenum pass) { m_stencil_func = func; m_stencil_spass_dpass_op = pass; }
void SetupDepth()
{
if (GLState::depth != m_depth_enable) {
GLState::depth = m_depth_enable;
if (m_depth_enable)
glEnable(GL_DEPTH_TEST);
else
glDisable(GL_DEPTH_TEST);
}
if (m_depth_enable) {
if (GLState::depth_func != m_depth_func) {
GLState::depth_func = m_depth_func;
glDepthFunc(m_depth_func);
}
if (GLState::depth_mask != m_depth_mask) {
GLState::depth_mask = m_depth_mask;
glDepthMask((GLboolean)m_depth_mask);
}
}
}
void SetupStencil()
{
if (GLState::stencil != m_stencil_enable) {
GLState::stencil = m_stencil_enable;
if (m_stencil_enable)
glEnable(GL_STENCIL_TEST);
else
glDisable(GL_STENCIL_TEST);
}
if (m_stencil_enable) {
// Note: here the mask control which bitplane is considered by the operation
if (GLState::stencil_func != m_stencil_func) {
GLState::stencil_func = m_stencil_func;
glStencilFunc(m_stencil_func, 1, 1);
}
if (GLState::stencil_pass != m_stencil_spass_dpass_op) {
GLState::stencil_pass = m_stencil_spass_dpass_op;
glStencilOp(GL_KEEP, GL_KEEP, m_stencil_spass_dpass_op);
}
}
}
bool IsMaskEnable() { return m_depth_mask != GL_FALSE; }
};
class GSDeviceOGL final : public GSDevice
{
public:
__aligned(struct, 32) VSConstantBuffer
{
GSVector4 Vertex_Scale_Offset;
GSVector4 TextureScale;
VSConstantBuffer()
{
Vertex_Scale_Offset = GSVector4::zero();
TextureScale = GSVector4::zero();
}
__forceinline bool Update(const VSConstantBuffer* cb)
{
GSVector4i* a = (GSVector4i*)this;
GSVector4i* b = (GSVector4i*)cb;
if(!((a[0] == b[0]) & (a[1] == b[1])).alltrue())
{
a[0] = b[0];
a[1] = b[1];
return true;
}
return false;
}
};
struct VSSelector
{
union
{
struct
{
uint32 wildhack:1;
uint32 bppz:2;
uint32 _free:29;
};
uint32 key;
};
operator uint32() {return key;}
VSSelector() : key(0) {}
VSSelector(uint32 k) : key(k) {}
};
struct GSSelector
{
union
{
struct
{
uint32 sprite:1;
uint32 point:1;
uint32 _free:30;
};
uint32 key;
};
operator uint32() {return key;}
GSSelector() : key(0) {}
GSSelector(uint32 k) : key(k) {}
};
__aligned(struct, 32) PSConstantBuffer
{
GSVector4 FogColor_AREF;
GSVector4 WH;
GSVector4 TA_Af;
GSVector4i MskFix;
GSVector4i FbMask;
GSVector4 HalfTexel;
GSVector4 MinMax;
GSVector4 TC_OH_TS;
PSConstantBuffer()
{
FogColor_AREF = GSVector4::zero();
HalfTexel = GSVector4::zero();
WH = GSVector4::zero();
MinMax = GSVector4::zero();
MskFix = GSVector4i::zero();
TC_OH_TS = GSVector4::zero();
FbMask = GSVector4i::zero();
}
__forceinline bool Update(const PSConstantBuffer* cb)
{
GSVector4i* a = (GSVector4i*)this;
GSVector4i* b = (GSVector4i*)cb;
// if WH matches both HalfTexel and TC_OH_TS do too
// MinMax depends on WH and MskFix so no need to check it too
if(!((a[0] == b[0]) & (a[1] == b[1]) & (a[2] == b[2]) & (a[3] == b[3]) & (a[4] == b[4])).alltrue())
{
// Note previous check uses SSE already, a plain copy will be faster than any memcpy
a[0] = b[0];
a[1] = b[1];
a[2] = b[2];
a[3] = b[3];
a[4] = b[4];
a[5] = b[5];
return true;
}
return false;
}
};
struct PSSelector
{
// Performance note: there are too many shader combinations
// It might hurt the performance due to frequent toggling worse it could consume
// a lots of memory.
union
{
struct
{
// *** Word 1
// Format
uint32 tex_fmt:4;
uint32 dfmt:2;
// Alpha extension/Correction
uint32 aem:1;
uint32 fba:1;
// Fog
uint32 fog:1;
// Flat/goround shading
uint32 iip:1;
// Pixel test
uint32 date:3;
uint32 atst:3;
// Color sampling
uint32 fst:1; // Investigate to do it on the VS
uint32 tfx:3;
uint32 tcc:1;
uint32 wms:2;
uint32 wmt:2;
uint32 ltf:1;
// Shuffle and fbmask effect
uint32 shuffle:1;
uint32 read_ba:1;
uint32 write_rg:1;
uint32 fbmask:1;
uint32 _free1:2;
// *** Word 2
// Blend and Colclip
uint32 blend_a:2;
uint32 blend_b:2;
uint32 blend_c:2;
uint32 blend_d:2;
uint32 clr1:1; // useful?
uint32 pabe:1;
uint32 hdr:1;
uint32 colclip:1;
// Hack
uint32 tcoffsethack:1;
uint32 _free2:19;
};
uint64 key;
};
// FIXME is the & useful ?
operator uint64() {return key;}
PSSelector() : key(0) {}
};
struct PSSamplerSelector
{
union
{
struct
{
uint32 tau:1;
uint32 tav:1;
uint32 ltf:1;
uint32 aniso:1;
uint32 _free:28;
};
uint32 key;
};
operator uint32() {return key;}
PSSamplerSelector() : key(0) {}
PSSamplerSelector(uint32 k) : key(k) {}
};
struct OMDepthStencilSelector
{
union
{
struct
{
uint32 ztst:2;
uint32 zwe:1;
uint32 date:1;
uint32 _free:28;
};
uint32 key;
};
// FIXME is the & useful ?
operator uint32() {return key;}
OMDepthStencilSelector() : key(0) {}
OMDepthStencilSelector(uint32 k) : key(k) {}
};
struct OMColorMaskSelector
{
union
{
struct
{
uint32 wr:1;
uint32 wg:1;
uint32 wb:1;
uint32 wa:1;
uint32 _free:28;
};
struct
{
uint32 wrgba:4;
};
uint32 key;
};
// FIXME is the & useful ?
operator uint32() {return key & 0xf;}
OMColorMaskSelector() : key(0xF) {}
OMColorMaskSelector(uint32 c) { wrgba = c; }
};
struct OGLBlend {uint16 bogus, op, src, dst;};
static const OGLBlend m_blendMapOGL[3*3*3*3 + 1];
static const int m_NO_BLEND;
static const int m_MERGE_BLEND;
static int s_n;
private:
uint32 m_msaa; // Level of Msaa
static bool m_debug_gl_call;
static FILE* m_debug_gl_file;
GSWnd* m_window;
GLuint m_fbo; // frame buffer container
GLuint m_fbo_read; // frame buffer container only for reading
GSVertexBufferStateOGL* m_va;// state of the vertex buffer/array
struct {
GLuint ps[2]; // program object
GSUniformBufferOGL* cb; // uniform buffer object
} m_merge_obj;
struct {
GLuint ps[4]; // program object
GSUniformBufferOGL* cb; // uniform buffer object
} m_interlace;
struct {
GLuint vs; // program object
GLuint ps[18]; // program object
GLuint ln; // sampler object
GLuint pt; // sampler object
GSDepthStencilOGL* dss;
GSDepthStencilOGL* dss_write;
GSUniformBufferOGL* cb;
} m_convert;
struct {
GLuint ps;
GSUniformBufferOGL *cb;
} m_fxaa;
struct {
GLuint ps;
GSUniformBufferOGL* cb;
} m_shaderfx;
struct {
GSDepthStencilOGL* dss;
GSTexture* t;
} m_date;
struct {
GLuint ps;
GSUniformBufferOGL *cb;
} m_shadeboost;
GLuint m_vs[1<<3];
GLuint m_gs[1<<2];
GLuint m_ps_ss[1<<4];
GSDepthStencilOGL* m_om_dss[1<<4];
hash_map<uint64, GLuint > m_ps;
GLuint m_apitrace;
GLuint m_palette_ss;
GSUniformBufferOGL* m_vs_cb;
GSUniformBufferOGL* m_ps_cb;
VSConstantBuffer m_vs_cb_cache;
PSConstantBuffer m_ps_cb_cache;
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* sTex[2], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, bool slbg, bool mmod, const GSVector4& c) final;
void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset = 0) final;
void DoFXAA(GSTexture* sTex, GSTexture* dTex) final;
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex) final;
void DoExternalFX(GSTexture* sTex, GSTexture* dTex) final;
void OMAttachRt(GSTextureOGL* rt = NULL);
void OMAttachDs(GSTextureOGL* ds = NULL);
void OMSetFBO(GLuint fbo);
public:
GSShaderOGL* m_shader;
GSDeviceOGL();
virtual ~GSDeviceOGL();
static void CheckDebugLog();
// Used by OpenGL, so the same calling convention is required.
static void APIENTRY DebugOutputToFile(GLenum gl_source, GLenum gl_type, GLuint id, GLenum gl_severity, GLsizei gl_length, const GLchar *gl_message, const void* userParam);
bool HasStencil() { return true; }
bool HasDepth32() { return true; }
bool Create(GSWnd* wnd);
bool Reset(int w, int h);
void Flip();
void SetVSync(bool enable);
void DrawPrimitive() final;
void DrawPrimitive(int offset, int count);
void DrawIndexedPrimitive() final;
void DrawIndexedPrimitive(int offset, int count) final;
inline void BeforeDraw();
inline void AfterDraw();
void ClearRenderTarget(GSTexture* t, const GSVector4& c) final;
void ClearRenderTarget(GSTexture* t, uint32 c) final;
void ClearRenderTarget_i(GSTexture* t, int32 c);
void ClearDepth(GSTexture* t, float c) final;
void ClearStencil(GSTexture* t, uint8 c) final;
GSTexture* CreateRenderTarget(int w, int h, bool msaa, int format = 0) final;
GSTexture* CreateDepthStencil(int w, int h, bool msaa, int format = 0) final;
GSTexture* CreateTexture(int w, int h, int format = 0) final;
GSTexture* CreateOffscreen(int w, int h, int format = 0) final;
void InitPrimDateTexture(GSTexture* rt);
void RecycleDateTexture();
GSTexture* CopyOffscreen(GSTexture* src, const GSVector4& sRect, int w, int h, int format = 0, int ps_shader = 0) final;
void CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r) final;
void CopyRectConv(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, bool at_origin);
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, int shader = 0, bool linear = true) final;
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, GLuint ps, bool linear = true);
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, GLuint ps, int bs, bool linear = true);
void SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1* vertices, bool datm);
void BeginScene() final {}
void EndScene() final;
void IASetPrimitiveTopology(GLenum topology);
void IASetVertexBuffer(const void* vertices, size_t count);
void IASetIndexBuffer(const void* index, size_t count);
void PSSetShaderResource(int i, GSTexture* sr) final;
void PSSetShaderResources(GSTexture* sr0, GSTexture* sr1) final;
void PSSetSamplerState(GLuint ss);
void OMSetDepthStencilState(GSDepthStencilOGL* dss);
void OMSetBlendState(uint8 blend_index = 0, uint8 blend_factor = 0, bool is_blend_constant = false);
void OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i* scissor = NULL) final;
void OMSetColorMaskState(OMColorMaskSelector sel = OMColorMaskSelector());
void CreateTextureFX();
GLuint CompileVS(VSSelector sel, int logz);
GLuint CompileGS(GSSelector sel);
GLuint CompilePS(PSSelector sel);
GLuint CreateSampler(bool bilinear, bool tau, bool tav, bool aniso = false);
GLuint CreateSampler(PSSamplerSelector sel);
GSDepthStencilOGL* CreateDepthStencil(OMDepthStencilSelector dssel);
void SelfShaderTest();
void SetupIA(const void* vertex, int vertex_count, const uint32* index, int index_count, int prim);
void SetupVS(VSSelector sel);
void SetupGS(GSSelector sel);
void SetupPS(PSSelector sel);
void SetupCB(const VSConstantBuffer* vs_cb, const PSConstantBuffer* ps_cb);
void SetupSampler(PSSamplerSelector ssel);
void SetupOM(OMDepthStencilSelector dssel);
GLuint GetSamplerID(PSSamplerSelector ssel);
GLuint GetPaletteSamplerID();
void Barrier(GLbitfield b);
};

View File

@ -0,0 +1,436 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSDeviceSW.h"
GSDeviceSW::GSDeviceSW()
{
}
bool GSDeviceSW::Create(GSWnd* wnd)
{
if(!GSDevice::Create(wnd))
return false;
Reset(1, 1);
return true;
}
bool GSDeviceSW::Reset(int w, int h)
{
if(!GSDevice::Reset(w, h))
return false;
// TODO: m_backbuffer should be a window wrapper, or some native bitmap, software-only StretchRect to a full screen window may be too slow
m_backbuffer = new GSTextureSW(GSTexture::RenderTarget, w, h);
return true;
}
GSTexture* GSDeviceSW::CreateSurface(int type, int w, int h, bool msaa, int format)
{
if(format != 0) return NULL; // there is only one format
return new GSTextureSW(type, w, h);
}
void GSDeviceSW::BeginScene()
{
// TODO
}
void GSDeviceSW::DrawPrimitive()
{
// TODO
}
void GSDeviceSW::EndScene()
{
// TODO
}
void GSDeviceSW::ClearRenderTarget(GSTexture* t, const GSVector4& c)
{
Clear(t, (c * 255 + 0.5f).rgba32());
}
void GSDeviceSW::ClearRenderTarget(GSTexture* t, uint32 c)
{
Clear(t, c);
}
void GSDeviceSW::ClearDepth(GSTexture* t, float c)
{
Clear(t, *(uint32*)&c);
}
void GSDeviceSW::ClearStencil(GSTexture* t, uint8 c)
{
Clear(t, c);
}
GSTexture* GSDeviceSW::CopyOffscreen(GSTexture* src, const GSVector4& sRect, int w, int h, int format, int ps_shader)
{
GSTexture* dst = CreateOffscreen(w, h, format);
if(dst != NULL)
{
CopyRect(src, dst, GSVector4i(0, 0, w, h));
}
return dst;
}
void GSDeviceSW::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r)
{
GSTexture::GSMap m;
if(sTex->Map(m, &r))
{
dTex->Update(r, m.bits, m.pitch);
sTex->Unmap();
}
}
class ShaderBase
{
protected:
GSVector4i Sample(const GSVector4i& c, const GSVector4i& uf, const GSVector4i& vf) const
{
GSVector4i c0 = c.upl8();
GSVector4i c1 = c.uph8();
c0 = c0.lerp16<0>(c1, vf);
c0 = c0.lerp16<0>(c0.srl<8>(), uf);
return c0;
}
GSVector4i Blend(const GSVector4i& c0, const GSVector4i& c1) const
{
return c0.lerp16<0>(c1, c1.wwwwl().sll16(7));
}
GSVector4i Blend2x(const GSVector4i& c0, const GSVector4i& c1) const
{
return c0.lerp16<0>(c1, c1.wwwwl().sll16(1).pu16().uph8().sll16(7)); // .sll16(1).pu16() => 2x, then clamp (...)
}
GSVector4i Blend(const GSVector4i& c0, const GSVector4i& c1, const GSVector4i& f) const
{
return c0.lerp16<0>(c1, f);
}
};
class ShaderCopy : public ShaderBase
{
public:
void operator() (uint32* RESTRICT dst, const GSVector4i& c, const GSVector4i& uf, const GSVector4i& vf) const
{
*dst = Sample(c, uf, vf).pu16().extract32<0>();
}
void operator() (uint32* RESTRICT dst, uint32 c) const
{
*dst = c;
}
};
class ShaderAlphaBlend : public ShaderBase
{
public:
void operator() (uint32* RESTRICT dst, const GSVector4i& c, const GSVector4i& uf, const GSVector4i& vf) const
{
*dst = Blend(Sample(c, uf, vf), GSVector4i(*dst).uph8()).pu16().extract32<0>();
}
void operator() (uint32* RESTRICT dst, uint32 c) const
{
*dst = Blend(GSVector4i(c), GSVector4i(*dst).uph8()).pu16().extract32<0>();
}
};
class ShaderAlpha2xBlend : public ShaderBase
{
public:
void operator() (uint32* RESTRICT dst, const GSVector4i& c, const GSVector4i& uf, const GSVector4i& vf) const
{
*dst = Blend2x(Sample(c, uf, vf), GSVector4i(*dst).uph8()).pu16().extract32<0>();
}
void operator() (uint32* RESTRICT dst, uint32 c) const
{
*dst = Blend2x(GSVector4i(c), GSVector4i(*dst).uph8()).pu16().extract32<0>();
}
};
__aligned(class, 16) ShaderFactorBlend : public ShaderBase
{
GSVector4i m_f;
public:
ShaderFactorBlend(uint32 f)
{
m_f = GSVector4i((f << 16) | f).xxxx().srl16(1);
}
void operator() (uint32* RESTRICT dst, const GSVector4i& c, const GSVector4i& uf, const GSVector4i& vf) const
{
*dst = Blend(Sample(c, uf, vf), GSVector4i(*dst).uph8(), m_f).pu16().extract32<0>();
}
void operator() (uint32* RESTRICT dst, uint32 c) const
{
*dst = Blend(GSVector4i(c), GSVector4i(*dst).uph8(), m_f).pu16().extract32<0>();
}
};
template<class SHADER> static void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, const SHADER& shader, bool linear)
{
GSVector4i r(dRect.ceil());
r = r.rintersect(GSVector4i(dTex->GetSize()).zwxy());
if(r.rempty()) return;
GSTexture::GSMap dm;
if(!dTex->Map(dm, &r)) return;
GSTexture::GSMap sm;
if(!sTex->Map(sm, NULL)) {dTex->Unmap(); return;}
GSVector2i ssize = sTex->GetSize();
GSVector4 p = dRect;
GSVector4 t = sRect * GSVector4(ssize).xyxy() * GSVector4((float)0x10000);
GSVector4 tl = p.xyxy(t);
GSVector4 br = p.zwzw(t);
GSVector4 tlbr = br - tl;
tlbr /= tlbr.xyxy();
if(tl.x < (float)r.left) tl.z += tlbr.z * ((float)r.left - tl.x);
if(tl.y < (float)r.top) tl.w += tlbr.w * ((float)r.top - tl.y);
GSVector4i uvdudv(tl.zwzw(tlbr));
GSVector4i uv = uvdudv.xxyy() + GSVector4i(0, 0x10000).xyxy();
GSVector4i du = uvdudv.zzzz().srl<8>();
GSVector4i dv = uvdudv.wwww().sll<8>();
// TODO: clipping may not be that necessary knowing we don't address outside (except the linear filter +1 pixel)
GSVector4i uvmax = GSVector4i((ssize.x - 1) << 16, (ssize.y - 1) << 16).xxyy();
GSVector4i v = uv;
if(linear)
{
for(int j = r.height(); j > 0; j--, v += dv, dm.bits += dm.pitch)
{
GSVector4i vf = v.zzwwh().zzww().srl16(1);
GSVector4i vi = v.max_i16(GSVector4i::zero()).min_i16(uvmax);
int v0 = vi.extract16<5>();
int v1 = vi.extract16<7>();
uint32* RESTRICT src0 = (uint32*)&sm.bits[v0 * sm.pitch];
uint32* RESTRICT src1 = (uint32*)&sm.bits[v1 * sm.pitch];
uint32* RESTRICT dst = (uint32*)dm.bits;
GSVector4i u = v;
for(int i = r.width(); i > 0; i--, dst++, u += du)
{
GSVector4i uf = u.xxyyh().xxyy().srl16(1);
GSVector4i ui = u.max_i16(GSVector4i::zero()).min_i16(uvmax);
int u0 = ui.extract16<1>();
int u1 = ui.extract16<3>();
shader(dst, GSVector4i(src0[u0], src0[u1], src1[u0], src1[u1]), uf, vf);
}
}
}
else
{
for(int j = r.height(); j > 0; j--, v += dv, dm.bits += dm.pitch)
{
GSVector4i vi = v.max_i16(GSVector4i::zero()).min_i16(uvmax);
uint32* RESTRICT src = (uint32*)&sm.bits[vi.extract16<5>() * sm.pitch];
uint32* RESTRICT dst = (uint32*)dm.bits;
GSVector4i u = v;
for(int i = r.width(); i > 0; i--, dst++, u += du)
{
GSVector4i ui = u.max_i16(GSVector4i::zero()).min_i16(uvmax);
shader(dst, src[ui.extract16<1>()]);
}
}
}
sTex->Unmap();
dTex->Unmap();
}
void GSDeviceSW::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, int shader, bool linear)
{
// TODO: if dTex == m_backbuffer && m_backbuffer is special
if(shader == 0)
{
if((sRect == GSVector4(0, 0, 1, 1) & dRect == GSVector4(dTex->GetSize()).zwxy()).alltrue() && sTex->GetSize() == dTex->GetSize())
{
// shortcut
CopyRect(sTex, dTex, GSVector4i(dTex->GetSize()).zwxy());
return;
}
ShaderCopy s;
::StretchRect(sTex, sRect, dTex, dRect, s, linear);
}
else if(shader == 1)
{
ShaderAlphaBlend s;
::StretchRect(sTex, sRect, dTex, dRect, s, linear);
}
else
{
ASSERT(0);
}
}
void GSDeviceSW::PSSetShaderResources(GSTexture* sr0, GSTexture* sr1)
{
// TODO
}
void GSDeviceSW::PSSetShaderResource(int i, GSTexture* sRect)
{
// TODO
}
void GSDeviceSW::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i* scissor)
{
// TODO
}
//
void GSDeviceSW::DoMerge(GSTexture* sTex[2], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, bool slbg, bool mmod, const GSVector4& c)
{
ClearRenderTarget(dTex, c);
if(sTex[1] && !slbg)
{
StretchRect(sTex[1], sRect[1], dTex, dRect[1]);
}
if(sTex[0])
{
if(mmod == 0)
{
// alpha = min(sTex[0].a * 2, 1)
ShaderAlpha2xBlend s;
::StretchRect(sTex[0], sRect[0], dTex, dRect[0], s, true);
}
else
{
// alpha = c.a
ShaderFactorBlend s((uint32)(int)(c.a * 255));
::StretchRect(sTex[0], sRect[0], dTex, dRect[0], s, true);
}
}
// dTex->Save("c:\\1.bmp");
}
void GSDeviceSW::DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset)
{
GSVector4 s = GSVector4(dTex->GetSize());
GSVector4 sRect(0, 0, 1, 1);
GSVector4 dRect(0.0f, yoffset, s.x, s.y + yoffset);
if(shader == 0 || shader == 1)
{
// TODO: 0/1 => update even/odd lines of dTex
}
else if(shader == 2)
{
// TODO: blend lines (1:2:1 filter)
}
else if(shader == 3)
{
StretchRect(sTex, sRect, dTex, dRect, 0, linear);
}
else
{
ASSERT(0);
}
}
void GSDeviceSW::Clear(GSTexture* t, uint32 c)
{
int w = t->GetWidth();
int h = t->GetHeight();
GSTexture::GSMap m;
if(t->Map(m, NULL))
{
GSVector4i v((int)c);
w >>= 2;
for(int j = 0; j < h; j++, m.bits += m.pitch)
{
GSVector4i* RESTRICT dst = (GSVector4i*)m.bits;
for(int i = 0; i < w; i += 2)
{
dst[i + 0] = v;
dst[i + 1] = v;
}
}
t->Unmap();
}
}

View File

@ -0,0 +1,62 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSDevice.h"
#include "GSTextureSW.h"
class GSDeviceSW : public GSDevice
{
GSTexture* CreateSurface(int type, int w, int h, bool msaa, int format);
void DoMerge(GSTexture* sTex[2], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, bool slbg, bool mmod, const GSVector4& c);
void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset = 0);
void Clear(GSTexture* t, uint32 c);
public:
GSDeviceSW();
bool Create(GSWnd* wnd);
bool Reset(int w, int h);
// drawing may be routed through here, the software renderers use the rasterizer directly now
void BeginScene();
void DrawPrimitive();
void EndScene();
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* CopyOffscreen(GSTexture* src, const GSVector4& sRect, int w, int h, int format = 0, int ps_shader = 0);
void CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r);
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, int shader = 0, bool linear = true);
void PSSetShaderResources(GSTexture* sr0, GSTexture* sr1);
void PSSetShaderResource(int i, GSTexture* sRect);
void OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i* scissor = NULL);
};

View File

@ -0,0 +1,336 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "StdAfx.h"
#include <Shlwapi.h>
#include <CommCtrl.h>
#include "GSdx.h"
#include "GSDialog.h"
#include "GSVector.h"
GSDialog::GSDialog(UINT id)
: m_id(id)
, m_hWnd(NULL)
{
}
INT_PTR GSDialog::DoModal()
{
return DialogBoxParam(theApp.GetModuleHandle(), MAKEINTRESOURCE(m_id), GetActiveWindow(), DialogProc, (LPARAM)this);
}
INT_PTR CALLBACK GSDialog::DialogProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
GSDialog* dlg = NULL;
if(message == WM_INITDIALOG)
{
dlg = (GSDialog*)lParam;
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)dlg);
dlg->m_hWnd = hWnd;
MONITORINFO mi;
mi.cbSize = sizeof(mi);
GetMonitorInfo(MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST), &mi);
GSVector4i r;
GetWindowRect(hWnd, r);
int x = (mi.rcWork.left + mi.rcWork.right - r.width()) / 2;
int y = (mi.rcWork.top + mi.rcWork.bottom - r.height()) / 2;
SetWindowPos(hWnd, NULL, x, y, -1, -1, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
dlg->OnInit();
return true;
}
dlg = (GSDialog*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
if (message == WM_NOTIFY)
{
if (((LPNMHDR)lParam)->code == TTN_GETDISPINFO)
{
LPNMTTDISPINFO pInfo = (LPNMTTDISPINFO)lParam;
UINT id = GetWindowLongPtr((HWND)pInfo->hdr.idFrom, GWL_ID);
// lpszText is used only if hinst is NULL. Seems to be NULL already,
// but it can't hurt to explicitly set it.
pInfo->hinst = NULL;
pInfo->lpszText = (LPTSTR)dialog_message(id);
SendMessage(pInfo->hdr.hwndFrom, TTM_SETMAXTIPWIDTH, 0, 500);
return true;
}
}
return dlg != NULL ? dlg->OnMessage(message, wParam, lParam) : FALSE;
}
// Tooltips will only show if the TOOLINFO cbSize <= the struct size. If it's
// smaller some functionality might be disabled. So let's try and use the
// correct size.
UINT GSDialog::GetTooltipStructSize()
{
DLLGETVERSIONPROC dllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(GetModuleHandle("ComCtl32.dll"), "DllGetVersion");
if (dllGetVersion) {
DLLVERSIONINFO2 dllversion = { 0 };
dllversion.info1.cbSize = sizeof(DLLVERSIONINFO2);
if (dllGetVersion((DLLVERSIONINFO*)&dllversion) == S_OK) {
// Minor, then major version.
DWORD version = MAKELONG(dllversion.info1.dwMinorVersion, dllversion.info1.dwMajorVersion);
DWORD tooltip_v3 = MAKELONG(0, 6);
if (version >= tooltip_v3)
return TTTOOLINFOA_V3_SIZE;
}
}
// Should be fine for XP and onwards, comctl versions >= 4.7 should at least
// be this size.
return TTTOOLINFOA_V2_SIZE;
}
bool GSDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
{
return message == WM_COMMAND ? OnCommand((HWND)lParam, LOWORD(wParam), HIWORD(wParam)) : false;
}
bool GSDialog::OnCommand(HWND hWnd, UINT id, UINT code)
{
if(id == IDOK || id == IDCANCEL)
{
EndDialog(m_hWnd, id);
return true;
}
return false;
}
string GSDialog::GetText(UINT id)
{
string s;
char* buff = NULL;
for(int size = 256, limit = 65536; size < limit; size <<= 1)
{
buff = new char[size];
if(GetDlgItemText(m_hWnd, id, buff, size))
{
s = buff;
size = limit;
}
delete [] buff;
}
return s;
}
int GSDialog::GetTextAsInt(UINT id)
{
return atoi(GetText(id).c_str());
}
void GSDialog::SetText(UINT id, const char* str)
{
SetDlgItemText(m_hWnd, id, str);
}
void GSDialog::SetTextAsInt(UINT id, int i)
{
char buff[32] = {0};
itoa(i, buff, 10);
SetText(id, buff);
}
void GSDialog::ComboBoxInit(UINT id, const vector<GSSetting>& settings, int32_t selectionValue, int32_t maxValue)
{
HWND hWnd = GetDlgItem(m_hWnd, id);
SendMessage(hWnd, CB_RESETCONTENT, 0, 0);
for(size_t i = 0; i < settings.size(); i++)
{
const GSSetting& s = settings[i];
if(s.value <= maxValue)
{
string str(s.name);
if(!s.note.empty())
{
str = str + " (" + s.note + ")";
}
ComboBoxAppend(id, str.c_str(), (LPARAM)s.value, s.value == selectionValue);
}
}
ComboBoxFixDroppedWidth(id);
}
int GSDialog::ComboBoxAppend(UINT id, const char* str, LPARAM data, bool select)
{
HWND hWnd = GetDlgItem(m_hWnd, id);
int item = (int)SendMessage(hWnd, CB_ADDSTRING, 0, (LPARAM)str);
SendMessage(hWnd, CB_SETITEMDATA, item, (LPARAM)data);
if(select)
{
SendMessage(hWnd, CB_SETCURSEL, item, 0);
}
return item;
}
bool GSDialog::ComboBoxGetSelData(UINT id, INT_PTR& data)
{
HWND hWnd = GetDlgItem(m_hWnd, id);
int item = SendMessage(hWnd, CB_GETCURSEL, 0, 0);
if(item >= 0)
{
data = SendMessage(hWnd, CB_GETITEMDATA, item, 0);
return true;
}
return false;
}
void GSDialog::ComboBoxFixDroppedWidth(UINT id)
{
HWND hWnd = GetDlgItem(m_hWnd, id);
int count = (int)SendMessage(hWnd, CB_GETCOUNT, 0, 0);
if(count > 0)
{
HDC hDC = GetDC(hWnd);
SelectObject(hDC, (HFONT)SendMessage(hWnd, WM_GETFONT, 0, 0));
int width = (int)SendMessage(hWnd, CB_GETDROPPEDWIDTH, 0, 0);
for(int i = 0; i < count; i++)
{
int len = (int)SendMessage(hWnd, CB_GETLBTEXTLEN, i, 0);
if(len > 0)
{
char* buff = new char[len + 1];
SendMessage(hWnd, CB_GETLBTEXT, i, (LPARAM)buff);
SIZE size;
if(GetTextExtentPoint32(hDC, buff, strlen(buff), &size))
{
size.cx += 10;
if(size.cx > width) width = size.cx;
}
delete [] buff;
}
}
ReleaseDC(hWnd, hDC);
if(width > 0)
{
SendMessage(hWnd, CB_SETDROPPEDWIDTH, width, 0);
}
}
}
void GSDialog::OpenFileDialog(UINT id, const char *title)
{
char filename[512];
OPENFILENAME ofn = { 0 };
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = m_hWnd;
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST;
ofn.lpstrFile = filename;
ofn.lpstrFile[0] = 0;
ofn.nMaxFile = 512;
ofn.lpstrTitle = title;
// GetOpenFileName changes the current directory, so we need to save and
// restore the current directory or everything using relative paths will
// break.
char current_directory[512];
GetCurrentDirectory(512, current_directory);
if (GetOpenFileName(&ofn))
SendMessage(GetDlgItem(m_hWnd, id), WM_SETTEXT, 0, (LPARAM)filename);
SetCurrentDirectory(current_directory);
}
void GSDialog::AddTooltip(UINT id)
{
static UINT tooltipStructSize = GetTooltipStructSize();
bool hasTooltip;
dialog_message(id, &hasTooltip);
if (!hasTooltip)
return;
HWND hWnd = GetDlgItem(m_hWnd, id);
if (hWnd == NULL)
return;
// TTS_NOPREFIX allows tabs and '&' to be used.
HWND hwndTip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL,
TTS_ALWAYSTIP | TTS_NOPREFIX,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
m_hWnd, NULL, theApp.GetModuleHandle(), NULL);
if (hwndTip == NULL)
return;
TOOLINFO toolInfo = { 0 };
toolInfo.cbSize = tooltipStructSize;
toolInfo.hwnd = m_hWnd;
toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
toolInfo.uId = (UINT_PTR)hWnd;
// Can't directly add the tooltip string - it doesn't work for long messages
toolInfo.lpszText = LPSTR_TEXTCALLBACK;
SendMessage(hwndTip, TTM_ADDTOOL, 0, (LPARAM)&toolInfo);
// 32.767s is the max show time.
SendMessage(hwndTip, TTM_SETDELAYTIME, TTDT_AUTOPOP, 32767);
}
void GSDialog::InitCommonControls()
{
INITCOMMONCONTROLSEX icex;
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_TAB_CLASSES;
InitCommonControlsEx(&icex);
}

View File

@ -0,0 +1,64 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSSetting.h"
class GSDialog
{
int m_id;
static INT_PTR CALLBACK DialogProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
static UINT GetTooltipStructSize();
protected:
HWND m_hWnd;
virtual void OnInit() {}
virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
virtual bool OnCommand(HWND hWnd, UINT id, UINT code);
public:
GSDialog(UINT id);
virtual ~GSDialog() {}
int GetId() const {return m_id;}
INT_PTR DoModal();
string GetText(UINT id);
int GetTextAsInt(UINT id);
void SetText(UINT id, const char* str);
void SetTextAsInt(UINT id, int i);
void ComboBoxInit(UINT id, const vector<GSSetting>& settings, int32_t selectionValue, int32_t maxValue = INT32_MAX);
int ComboBoxAppend(UINT id, const char* str, LPARAM data = 0, bool select = false);
bool ComboBoxGetSelData(UINT id, INT_PTR& data);
void ComboBoxFixDroppedWidth(UINT id);
void OpenFileDialog(UINT id, const char *title);
void AddTooltip(UINT id);
static void InitCommonControls();
};

View File

@ -0,0 +1,84 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSDirtyRect.h"
GSDirtyRect::GSDirtyRect()
: psm(PSM_PSMCT32)
{
left = top = right = bottom = 0;
}
GSDirtyRect::GSDirtyRect(const GSVector4i& r, uint32 psm)
: psm(psm)
{
left = r.left;
top = r.top;
right = r.right;
bottom = r.bottom;
}
GSVector4i GSDirtyRect::GetDirtyRect(const GIFRegTEX0& TEX0)
{
GSVector4i r;
GSVector2i src = GSLocalMemory::m_psm[psm].bs;
if(psm != TEX0.PSM)
{
GSVector2i dst = GSLocalMemory::m_psm[TEX0.PSM].bs;
r.left = left * dst.x / src.x;
r.top = top * dst.y / src.y;
r.right = right * dst.x / src.x;
r.bottom = bottom * dst.y / src.y;
}
else
{
r = GSVector4i(left, top, right, bottom).ralign<Align_Outside>(src);
}
return r;
}
//
GSVector4i GSDirtyRectList::GetDirtyRectAndClear(const GIFRegTEX0& TEX0, const GSVector2i& size)
{
if(!empty())
{
GSVector4i r(INT_MAX, INT_MAX, 0, 0);
for(list<GSDirtyRect>::iterator i = begin(); i != end(); i++)
{
r = r.runion(i->GetDirtyRect(TEX0));
}
clear();
GSVector2i bs = GSLocalMemory::m_psm[TEX0.PSM].bs;
return r.ralign<Align_Outside>(bs).rintersect(GSVector4i(0, 0, size.x, size.y));
}
return GSVector4i::zero();
}

View File

@ -0,0 +1,46 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSLocalMemory.h"
class GSDirtyRect
{
int left;
int top;
int right;
int bottom;
uint32 psm;
public:
GSDirtyRect();
GSDirtyRect(const GSVector4i& r, uint32 psm);
GSVector4i GetDirtyRect(const GIFRegTEX0& TEX0);
};
class GSDirtyRectList : public list<GSDirtyRect>
{
public:
GSDirtyRectList() {}
GSVector4i GetDirtyRectAndClear(const GIFRegTEX0& TEX0, const GSVector2i& size);
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,90 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSState.h"
#include "GSRasterizer.h"
#include "GSScanlineEnvironment.h"
#include "GSSetupPrimCodeGenerator.h"
#include "GSDrawScanlineCodeGenerator.h"
class GSDrawScanline : public IDrawScanline
{
public:
class SharedData : public GSRasterizerData
{
public:
GSScanlineGlobalData global;
};
protected:
GSScanlineGlobalData m_global;
GSScanlineLocalData m_local;
GSCodeGeneratorFunctionMap<GSSetupPrimCodeGenerator, uint64, SetupPrimPtr> m_sp_map;
GSCodeGeneratorFunctionMap<GSDrawScanlineCodeGenerator, uint64, DrawScanlinePtr> m_ds_map;
template<class T, bool masked>
void DrawRectT(const int* RESTRICT row, const int* RESTRICT col, const GSVector4i& r, uint32 c, uint32 m);
template<class T, bool masked>
__forceinline void FillRect(const int* RESTRICT row, const int* RESTRICT col, const GSVector4i& r, uint32 c, uint32 m);
#if _M_SSE >= 0x501
template<class T, bool masked>
__forceinline void FillBlock(const int* RESTRICT row, const int* RESTRICT col, const GSVector4i& r, const GSVector8i& c, const GSVector8i& m);
#else
template<class T, bool masked>
__forceinline void FillBlock(const int* RESTRICT row, const int* RESTRICT col, const GSVector4i& r, const GSVector4i& c, const GSVector4i& m);
#endif
public:
GSDrawScanline();
virtual ~GSDrawScanline();
// IDrawScanline
void BeginDraw(const GSRasterizerData* data);
void EndDraw(uint64 frame, uint64 ticks, int actual, int total);
void DrawRect(const GSVector4i& r, const GSVertexSW& v);
#ifndef ENABLE_JIT_RASTERIZER
void SetupPrim(const GSVertexSW* vertex, const uint32* index, const GSVertexSW& dscan);
void DrawScanline(int pixels, int left, int top, const GSVertexSW& scan);
void DrawEdge(int pixels, int left, int top, const GSVertexSW& scan);
bool IsEdge() const {return m_global.sel.aa1;}
bool IsRect() const {return m_global.sel.IsSolidRect();}
template<class T> bool TestAlpha(T& test, T& fm, T& zm, const T& ga);
template<class T> void WritePixel(const T& src, int addr, int i, uint32 psm);
#endif
void PrintStats() {m_ds_map.PrintStats();}
};

View File

@ -0,0 +1,357 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSDrawScanlineCodeGenerator.h"
#if _M_SSE >= 0x501
__aligned(const uint8, 8) GSDrawScanlineCodeGenerator::m_test[16][8] =
{
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00},
{0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00},
{0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00},
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00},
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00},
{0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
{0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
{0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff},
{0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff},
{0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
};
const GSVector8 GSDrawScanlineCodeGenerator::m_log2_coef[4] =
{
GSVector8(0.204446009836232697516f),
GSVector8(-1.04913055217340124191f),
GSVector8(2.28330284476918490682f),
GSVector8(1.0f),
};
#else
const GSVector4i GSDrawScanlineCodeGenerator::m_test[8] =
{
GSVector4i::zero(),
GSVector4i(0xffffffff, 0x00000000, 0x00000000, 0x00000000),
GSVector4i(0xffffffff, 0xffffffff, 0x00000000, 0x00000000),
GSVector4i(0xffffffff, 0xffffffff, 0xffffffff, 0x00000000),
GSVector4i(0x00000000, 0xffffffff, 0xffffffff, 0xffffffff),
GSVector4i(0x00000000, 0x00000000, 0xffffffff, 0xffffffff),
GSVector4i(0x00000000, 0x00000000, 0x00000000, 0xffffffff),
GSVector4i::zero(),
};
const GSVector4 GSDrawScanlineCodeGenerator::m_log2_coef[4] =
{
GSVector4(0.204446009836232697516f),
GSVector4(-1.04913055217340124191f),
GSVector4(2.28330284476918490682f),
GSVector4(1.0f),
};
#endif
GSDrawScanlineCodeGenerator::GSDrawScanlineCodeGenerator(void* param, uint64 key, void* code, size_t maxsize)
: GSCodeGenerator(code, maxsize)
, m_local(*(GSScanlineLocalData*)param)
{
m_sel.key = key;
Generate();
}
#if _M_SSE >= 0x501
void GSDrawScanlineCodeGenerator::modulate16(const Ymm& a, const Operand& f, int shift)
{
if(shift == 0)
{
vpmulhrsw(a, f);
}
else
{
vpsllw(a, (uint8)(shift + 1));
vpmulhw(a, f);
}
}
void GSDrawScanlineCodeGenerator::lerp16(const Ymm& a, const Ymm& b, const Ymm& f, int shift)
{
vpsubw(a, b);
modulate16(a, f, shift);
vpaddw(a, b);
}
void GSDrawScanlineCodeGenerator::lerp16_4(const Ymm& a, const Ymm& b, const Ymm& f)
{
vpsubw(a, b);
vpmullw(a, f);
vpsraw(a, 4);
vpaddw(a, b);
}
void GSDrawScanlineCodeGenerator::mix16(const Ymm& a, const Ymm& b, const Ymm& temp)
{
vpblendw(a, b, 0xaa);
}
void GSDrawScanlineCodeGenerator::clamp16(const Ymm& a, const Ymm& temp)
{
vpackuswb(a, a);
vpermq(a, a, _MM_SHUFFLE(3, 1, 2, 0)); // this sucks
vpmovzxbw(a, a);
}
void GSDrawScanlineCodeGenerator::alltrue()
{
vpmovmskb(eax, ymm7);
cmp(eax, 0xffffffff);
je("step", T_NEAR);
}
void GSDrawScanlineCodeGenerator::blend(const Ymm& a, const Ymm& b, const Ymm& mask)
{
vpand(b, mask);
vpandn(mask, a);
vpor(a, b, mask);
}
void GSDrawScanlineCodeGenerator::blendr(const Ymm& b, const Ymm& a, const Ymm& mask)
{
vpand(b, mask);
vpandn(mask, a);
vpor(b, mask);
}
void GSDrawScanlineCodeGenerator::blend8(const Ymm& a, const Ymm& b)
{
vpblendvb(a, a, b, xmm0);
}
void GSDrawScanlineCodeGenerator::blend8r(const Ymm& b, const Ymm& a)
{
vpblendvb(b, a, b, xmm0);
}
#else
void GSDrawScanlineCodeGenerator::modulate16(const Xmm& a, const Operand& f, int shift)
{
#if _M_SSE >= 0x500
if(shift == 0)
{
vpmulhrsw(a, f);
}
else
{
vpsllw(a, shift + 1);
vpmulhw(a, f);
}
#else
if(shift == 0 && m_cpu.has(util::Cpu::tSSSE3))
{
pmulhrsw(a, f);
}
else
{
psllw(a, shift + 1);
pmulhw(a, f);
}
#endif
}
void GSDrawScanlineCodeGenerator::lerp16(const Xmm& a, const Xmm& b, const Xmm& f, int shift)
{
#if _M_SSE >= 0x500
vpsubw(a, b);
modulate16(a, f, shift);
vpaddw(a, b);
#else
psubw(a, b);
modulate16(a, f, shift);
paddw(a, b);
#endif
}
void GSDrawScanlineCodeGenerator::lerp16_4(const Xmm& a, const Xmm& b, const Xmm& f)
{
#if _M_SSE >= 0x500
vpsubw(a, b);
vpmullw(a, f);
vpsraw(a, 4);
vpaddw(a, b);
#else
psubw(a, b);
pmullw(a, f);
psraw(a, 4);
paddw(a, b);
#endif
}
void GSDrawScanlineCodeGenerator::mix16(const Xmm& a, const Xmm& b, const Xmm& temp)
{
#if _M_SSE >= 0x500
vpblendw(a, b, 0xaa);
#elif _M_SSE >= 0x401
pblendw(a, b, 0xaa);
#else
pcmpeqd(temp, temp);
psrld(temp, 16);
pand(a, temp);
pandn(temp, b);
por(a, temp);
#endif
}
void GSDrawScanlineCodeGenerator::clamp16(const Xmm& a, const Xmm& temp)
{
#if _M_SSE >= 0x500
vpackuswb(a, a);
vpmovzxbw(a, a);
#elif _M_SSE >= 0x401
packuswb(a, a);
pmovzxbw(a, a);
#else
packuswb(a, a);
pxor(temp, temp);
punpcklbw(a, temp);
#endif
}
void GSDrawScanlineCodeGenerator::alltrue()
{
#if _M_SSE >= 0x500
vpmovmskb(eax, xmm7);
cmp(eax, 0xffff);
je("step", T_NEAR);
#else
pmovmskb(eax, xmm7);
cmp(eax, 0xffff);
je("step", T_NEAR);
#endif
}
void GSDrawScanlineCodeGenerator::blend(const Xmm& a, const Xmm& b, const Xmm& mask)
{
#if _M_SSE >= 0x500
vpand(b, mask);
vpandn(mask, a);
vpor(a, b, mask);
#else
pand(b, mask);
pandn(mask, a);
por(b, mask);
movdqa(a, b);
#endif
}
void GSDrawScanlineCodeGenerator::blendr(const Xmm& b, const Xmm& a, const Xmm& mask)
{
#if _M_SSE >= 0x500
vpand(b, mask);
vpandn(mask, a);
vpor(b, mask);
#else
pand(b, mask);
pandn(mask, a);
por(b, mask);
#endif
}
void GSDrawScanlineCodeGenerator::blend8(const Xmm& a, const Xmm& b)
{
#if _M_SSE >= 0x500
vpblendvb(a, a, b, xmm0);
#elif _M_SSE >= 0x401
pblendvb(a, b);
#else
blend(a, b, xmm0);
#endif
}
void GSDrawScanlineCodeGenerator::blend8r(const Xmm& b, const Xmm& a)
{
#if _M_SSE >= 0x500
vpblendvb(b, a, b, xmm0);
#elif _M_SSE >= 0x401
pblendvb(a, b);
movdqa(b, a);
#else
blendr(b, a, xmm0);
#endif
}
#endif

View File

@ -0,0 +1,145 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSScanlineEnvironment.h"
#include "GSFunctionMap.h"
using namespace Xbyak;
class GSDrawScanlineCodeGenerator : public GSCodeGenerator
{
void operator = (const GSDrawScanlineCodeGenerator&);
GSScanlineSelector m_sel;
GSScanlineLocalData& m_local;
void Generate();
#if _M_SSE >= 0x501
void Init();
void Step();
void TestZ(const Ymm& temp1, const Ymm& temp2);
void SampleTexture();
void Wrap(const Ymm& uv0);
void Wrap(const Ymm& uv0, const Ymm& uv1);
void SampleTextureLOD();
void WrapLOD(const Ymm& uv0);
void WrapLOD(const Ymm& uv0, const Ymm& uv1);
void AlphaTFX();
void ReadMask();
void TestAlpha();
void ColorTFX();
void Fog();
void ReadFrame();
void TestDestAlpha();
void WriteMask();
void WriteZBuf();
void AlphaBlend();
void WriteFrame();
#if defined(_M_AMD64) || defined(_WIN64)
void ReadPixel(const Ymm& dst, const Ymm& temp, const Reg64& addr);
void WritePixel(const Ymm& src, const Ymm& temp, const Reg64& addr, const Reg32& mask, bool fast, int psm, int fz);
void WritePixel(const Xmm& src, const Reg64& addr, uint8 i, uint8 j, int psm);
#else
void ReadPixel(const Ymm& dst, const Ymm& temp, const Reg32& addr);
void WritePixel(const Ymm& src, const Ymm& temp, const Reg32& addr, const Reg32& mask, bool fast, int psm, int fz);
void WritePixel(const Xmm& src, const Reg32& addr, uint8 i, uint8 j, int psm);
#endif
void ReadTexel(int pixels, int mip_offset = 0);
void ReadTexel(const Ymm& dst, const Ymm& addr, uint8 i);
void modulate16(const Ymm& a, const Operand& f, int shift);
void lerp16(const Ymm& a, const Ymm& b, const Ymm& f, int shift);
void lerp16_4(const Ymm& a, const Ymm& b, const Ymm& f);
void mix16(const Ymm& a, const Ymm& b, const Ymm& temp);
void clamp16(const Ymm& a, const Ymm& temp);
void alltrue();
void blend(const Ymm& a, const Ymm& b, const Ymm& mask);
void blendr(const Ymm& b, const Ymm& a, const Ymm& mask);
void blend8(const Ymm& a, const Ymm& b);
void blend8r(const Ymm& b, const Ymm& a);
#else
void Init();
void Step();
void TestZ(const Xmm& temp1, const Xmm& temp2);
void SampleTexture();
void Wrap(const Xmm& uv0);
void Wrap(const Xmm& uv0, const Xmm& uv1);
void SampleTextureLOD();
void WrapLOD(const Xmm& uv0);
void WrapLOD(const Xmm& uv0, const Xmm& uv1);
void AlphaTFX();
void ReadMask();
void TestAlpha();
void ColorTFX();
void Fog();
void ReadFrame();
void TestDestAlpha();
void WriteMask();
void WriteZBuf();
void AlphaBlend();
void WriteFrame();
#if defined(_M_AMD64) || defined(_WIN64)
void ReadPixel(const Xmm& dst, const Reg64& addr);
void WritePixel(const Xmm& src, const Reg64& addr, const Reg8& mask, bool fast, int psm, int fz);
void WritePixel(const Xmm& src, const Reg64& addr, uint8 i, int psm);
#else
void ReadPixel(const Xmm& dst, const Reg32& addr);
void WritePixel(const Xmm& src, const Reg32& addr, const Reg8& mask, bool fast, int psm, int fz);
void WritePixel(const Xmm& src, const Reg32& addr, uint8 i, int psm);
#endif
void ReadTexel(int pixels, int mip_offset = 0);
void ReadTexel(const Xmm& dst, const Xmm& addr, uint8 i);
void modulate16(const Xmm& a, const Operand& f, int shift);
void lerp16(const Xmm& a, const Xmm& b, const Xmm& f, int shift);
void lerp16_4(const Xmm& a, const Xmm& b, const Xmm& f);
void mix16(const Xmm& a, const Xmm& b, const Xmm& temp);
void clamp16(const Xmm& a, const Xmm& temp);
void alltrue();
void blend(const Xmm& a, const Xmm& b, const Xmm& mask);
void blendr(const Xmm& b, const Xmm& a, const Xmm& mask);
void blend8(const Xmm& a, const Xmm& b);
void blend8r(const Xmm& b, const Xmm& a);
#endif
public:
GSDrawScanlineCodeGenerator(void* param, uint64 key, void* code, size_t maxsize);
#if _M_SSE >= 0x501
static __aligned(const uint8, 8) m_test[16][8];
static const GSVector8 m_log2_coef[4];
#else
static const GSVector4i m_test[8];
static const GSVector4 m_log2_coef[4];
#endif
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,121 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSDrawScanlineCodeGenerator.h"
#if _M_SSE < 0x500 && (defined(_M_AMD64) || defined(_WIN64))
void GSDrawScanlineCodeGenerator::Generate()
{
}
void GSDrawScanlineCodeGenerator::Init()
{
}
void GSDrawScanlineCodeGenerator::Step()
{
}
void GSDrawScanlineCodeGenerator::TestZ(const Xmm& temp1, const Xmm& temp2)
{
}
void GSDrawScanlineCodeGenerator::SampleTexture()
{
}
void GSDrawScanlineCodeGenerator::Wrap(const Xmm& uv)
{
}
void GSDrawScanlineCodeGenerator::Wrap(const Xmm& uv0, const Xmm& uv1)
{
}
void GSDrawScanlineCodeGenerator::AlphaTFX()
{
}
void GSDrawScanlineCodeGenerator::ReadMask()
{
}
void GSDrawScanlineCodeGenerator::TestAlpha()
{
}
void GSDrawScanlineCodeGenerator::ColorTFX()
{
}
void GSDrawScanlineCodeGenerator::Fog()
{
}
void GSDrawScanlineCodeGenerator::ReadFrame()
{
}
void GSDrawScanlineCodeGenerator::TestDestAlpha()
{
}
void GSDrawScanlineCodeGenerator::WriteMask()
{
}
void GSDrawScanlineCodeGenerator::WriteZBuf()
{
}
void GSDrawScanlineCodeGenerator::AlphaBlend()
{
}
void GSDrawScanlineCodeGenerator::WriteFrame()
{
}
void GSDrawScanlineCodeGenerator::ReadPixel(const Xmm& dst, const Reg64& addr)
{
}
void GSDrawScanlineCodeGenerator::WritePixel(const Xmm& src, const Reg64& addr, const Reg8& mask, bool fast, int psm, int fz)
{
}
static const int s_offsets[4] = {0, 2, 8, 10};
void GSDrawScanlineCodeGenerator::WritePixel(const Xmm& src, const Reg64& addr, uint8 i, int psm)
{
}
void GSDrawScanlineCodeGenerator::ReadTexel(int pixels, int mip_offset)
{
}
void GSDrawScanlineCodeGenerator::ReadTexel(const Xmm& dst, const Xmm& addr, uint8 i)
{
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,138 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSDrawingContext.h"
#include "GSdx.h"
static int findmax(int tl, int br, int limit, int wm, int minuv, int maxuv)
{
// return max possible texcoord
int uv = br;
if(wm == CLAMP_CLAMP)
{
if(uv > limit) uv = limit;
}
else if(wm == CLAMP_REPEAT)
{
if(tl < 0) uv = limit; // wrap around
else if(uv > limit) uv = limit;
}
else if(wm == CLAMP_REGION_CLAMP)
{
if(uv < minuv) uv = minuv;
if(uv > maxuv) uv = maxuv;
}
else if(wm == CLAMP_REGION_REPEAT)
{
if(tl < 0) uv = minuv | maxuv; // wrap around, just use (any & mask) | fix
else uv = std::min(uv, minuv) | maxuv; // (any & mask) cannot be larger than mask, select br if that is smaller (not br & mask because there might be a larger value between tl and br when &'ed with the mask)
}
return uv;
}
static int reduce(int uv, int size)
{
while(size > 3 && (1 << (size - 1)) >= uv + 1)
{
size--;
}
return size;
}
static int extend(int uv, int size)
{
while(size < 10 && (1 << size) < uv + 1)
{
size++;
}
return size;
}
GIFRegTEX0 GSDrawingContext::GetSizeFixedTEX0(const GSVector4& st, bool linear, bool mipmap)
{
if(mipmap) return TEX0; // no mipmaping allowed
// find the optimal value for TW/TH by analyzing vertex trace and clamping values, extending only for region modes where uv may be outside
int tw = TEX0.TW;
int th = TEX0.TH;
int wms = (int)CLAMP.WMS;
int wmt = (int)CLAMP.WMT;
int minu = (int)CLAMP.MINU;
int minv = (int)CLAMP.MINV;
int maxu = (int)CLAMP.MAXU;
int maxv = (int)CLAMP.MAXV;
GSVector4 uvf = st;
if(linear)
{
uvf += GSVector4(-0.5f, 0.5f).xxyy();
}
GSVector4i uv = GSVector4i(uvf.floor());
uv.x = findmax(uv.x, uv.z, (1 << tw) - 1, wms, minu, maxu);
uv.y = findmax(uv.y, uv.w, (1 << th) - 1, wmt, minv, maxv);
if(tw + th >= 19) // smaller sizes aren't worth, they just create multiple entries in the textue cache and the saved memory is less
{
tw = reduce(uv.x, tw);
th = reduce(uv.y, th);
}
if(wms == CLAMP_REGION_CLAMP || wms == CLAMP_REGION_REPEAT)
{
tw = extend(uv.x, tw);
}
if(wmt == CLAMP_REGION_CLAMP || wmt == CLAMP_REGION_REPEAT)
{
th = extend(uv.y, th);
}
#ifdef _DEBUG
if(TEX0.TW != tw || TEX0.TH != th)
{
printf("FixedTEX0 %05x %d %d tw %d=>%d th %d=>%d st (%.0f,%.0f,%.0f,%.0f) uvmax %d,%d wm %d,%d (%d,%d,%d,%d)\n",
(int)TEX0.TBP0, (int)TEX0.TBW, (int)TEX0.PSM,
(int)TEX0.TW, tw, (int)TEX0.TH, th,
uvf.x, uvf.y, uvf.z, uvf.w,
uv.x, uv.y,
wms, wmt, minu, maxu, minv, maxv);
}
#endif
GIFRegTEX0 res = TEX0;
res.TW = tw;
res.TH = th;
return res;
}

View File

@ -0,0 +1,233 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GS.h"
#include "GSLocalMemory.h"
__aligned(class, 32) GSDrawingContext
{
public:
GIFRegXYOFFSET XYOFFSET;
GIFRegTEX0 TEX0;
GIFRegTEX1 TEX1;
GIFRegTEX2 TEX2;
GIFRegCLAMP CLAMP;
GIFRegMIPTBP1 MIPTBP1;
GIFRegMIPTBP2 MIPTBP2;
GIFRegSCISSOR SCISSOR;
GIFRegALPHA ALPHA;
GIFRegTEST TEST;
GIFRegFBA FBA;
GIFRegFRAME FRAME;
GIFRegZBUF ZBUF;
struct
{
GSVector4 in;
GSVector4i ex;
GSVector4 ofex;
GSVector4i ofxy;
} scissor;
struct
{
GSOffset* fb;
GSOffset* zb;
GSOffset* tex;
GSPixelOffset* fzb;
GSPixelOffset4* fzb4;
} offset;
GSDrawingContext()
{
memset(&offset, 0, sizeof(offset));
Reset();
}
void Reset()
{
memset(&XYOFFSET, 0, sizeof(XYOFFSET));
memset(&TEX0, 0, sizeof(TEX0));
memset(&TEX1, 0, sizeof(TEX1));
memset(&TEX2, 0, sizeof(TEX2));
memset(&CLAMP, 0, sizeof(CLAMP));
memset(&MIPTBP1, 0, sizeof(MIPTBP1));
memset(&MIPTBP2, 0, sizeof(MIPTBP2));
memset(&SCISSOR, 0, sizeof(SCISSOR));
memset(&ALPHA, 0, sizeof(ALPHA));
memset(&TEST, 0, sizeof(TEST));
memset(&FBA, 0, sizeof(FBA));
memset(&FRAME, 0, sizeof(FRAME));
memset(&ZBUF, 0, sizeof(ZBUF));
}
void UpdateScissor()
{
ASSERT(XYOFFSET.OFX <= 0xf800 && XYOFFSET.OFY <= 0xf800);
scissor.ex.u16[0] = (uint16)((SCISSOR.SCAX0 << 4) + XYOFFSET.OFX - 0x8000);
scissor.ex.u16[1] = (uint16)((SCISSOR.SCAY0 << 4) + XYOFFSET.OFY - 0x8000);
scissor.ex.u16[2] = (uint16)((SCISSOR.SCAX1 << 4) + XYOFFSET.OFX - 0x8000);
scissor.ex.u16[3] = (uint16)((SCISSOR.SCAY1 << 4) + XYOFFSET.OFY - 0x8000);
scissor.ofex = GSVector4(
(int)((SCISSOR.SCAX0 << 4) + XYOFFSET.OFX),
(int)((SCISSOR.SCAY0 << 4) + XYOFFSET.OFY),
(int)((SCISSOR.SCAX1 << 4) + XYOFFSET.OFX),
(int)((SCISSOR.SCAY1 << 4) + XYOFFSET.OFY));
scissor.in = GSVector4(
(int)SCISSOR.SCAX0,
(int)SCISSOR.SCAY0,
(int)SCISSOR.SCAX1 + 1,
(int)SCISSOR.SCAY1 + 1);
scissor.ofxy = GSVector4i(
0x8000,
0x8000,
(int)XYOFFSET.OFX - 15,
(int)XYOFFSET.OFY - 15);
}
bool DepthRead() const
{
return TEST.ZTE && TEST.ZTST >= 2;
}
bool DepthWrite() const
{
if(TEST.ATE && TEST.ATST == ATST_NEVER && TEST.AFAIL != AFAIL_ZB_ONLY) // alpha test, all pixels fail, z buffer is not updated
{
return false;
}
return ZBUF.ZMSK == 0 && TEST.ZTE != 0; // ZTE == 0 is bug on the real hardware, write is blocked then
}
GIFRegTEX0 GetSizeFixedTEX0(const GSVector4& st, bool linear, bool mipmap);
void Dump(const std::string& filename)
{
// Append on purpose so env + context are merged into a single file
FILE* fp = fopen(filename.c_str(), "at");
if (!fp) return;
fprintf(fp, "XYOFFSET\n"
"\tX:%d\n"
"\tY:%d\n\n"
, XYOFFSET.OFX, XYOFFSET.OFY);
fprintf(fp, "TEX0\n"
"\tTBP0:0x%x\n"
"\tTBW:%d\n"
"\tPSM:0x%x\n"
"\tTW:%d\n"
"\tTCC:%d\n"
"\tTFX:%d\n"
"\tCBP:0x%x\n"
"\tCPSM:0x%x\n"
"\tCSM:%d\n"
"\tCSA:%d\n"
"\tCLD:%d\n"
"\tTH:%lld\n\n"
, TEX0.TBP0, TEX0.TBW, TEX0.PSM, TEX0.TW, TEX0.TCC, TEX0.TFX, TEX0.CBP, TEX0.CPSM, TEX0.CSM, TEX0.CSA, TEX0.CLD, TEX0.TH);
fprintf(fp, "TEX1\n"
"\tLCM:%d\n"
"\tMXL:%d\n"
"\tMMAG:%d\n"
"\tMMIN:%d\n"
"\tMTBA:%d\n"
"\tL:%d\n"
"\tK:%d\n\n"
, TEX1.LCM, TEX1.MXL, TEX1.MMAG, TEX1.MMIN, TEX1.MTBA, TEX1.L, TEX1.K);
fprintf(fp, "TEX2\n"
"\tPSM:0x%x\n"
"\tCBP:0x%x\n"
"\tCPSM:0x%x\n"
"\tCSM:%d\n"
"\tCSA:%d\n"
"\tCLD:%d\n\n"
, TEX2.PSM, TEX2.CBP, TEX2.CPSM, TEX2.CSM, TEX2.CSA, TEX2.CLD);
fprintf(fp, "CLAMP\n"
"\tWMS:%d\n"
"\tWMT:%d\n"
"\tMINU:%d\n"
"\tMAXU:%d\n"
"\tMAXV:%d\n"
"\tMINV:%lld\n\n"
, CLAMP.WMS, CLAMP.WMT, CLAMP.MINU, CLAMP.MAXU, CLAMP.MAXV, CLAMP.MINV);
// TODO mimmap? (yes I'm lazy)
fprintf(fp, "SCISSOR\n"
"\tX0:%d\n"
"\tX1:%d\n"
"\tY0:%d\n"
"\tY1:%d\n\n"
, SCISSOR.SCAX0, SCISSOR.SCAX1, SCISSOR.SCAY0, SCISSOR.SCAY1);
fprintf(fp, "ALPHA\n"
"\tA:%d\n"
"\tB:%d\n"
"\tC:%d\n"
"\tD:%d\n"
"\tFIX:%d\n"
, ALPHA.A, ALPHA.B, ALPHA.C, ALPHA.D, ALPHA.FIX);
const char *col[3] = {"Cs", "Cd", "0"};
const char *alpha[3] = {"As", "Ad", "Af"};
fprintf(fp, "\t=> (%s - %s) * %s + %s\n\n", col[ALPHA.A], col[ALPHA.B], alpha[ALPHA.C], col[ALPHA.D]);
fprintf(fp, "TEST\n"
"\tATE:%d\n"
"\tATST:%d\n"
"\tAREF:%d\n"
"\tAFAIL:%d\n"
"\tDATE:%d\n"
"\tDATM:%d\n"
"\tZTE:%d\n"
"\tZTST:%d\n\n"
, TEST.ATE, TEST.ATST, TEST.AREF, TEST.AFAIL, TEST.DATE, TEST.DATM, TEST.ZTE, TEST.ZTST);
fprintf(fp, "FBA\n"
"\tFBA:%d\n\n"
, FBA.FBA);
fprintf(fp, "FRAME\n"
"\tFBP (*32):0x%x\n"
"\tFBW:%d\n"
"\tPSM:0x%x\n"
"\tFBMSK:0x%x\n\n"
, FRAME.FBP*32, FRAME.FBW, FRAME.PSM, FRAME.FBMSK);
fprintf(fp, "ZBUF\n"
"\tZBP (*32):0x%x\n"
"\tPSM:0x%x\n"
"\tZMSK:%d\n\n"
, ZBUF.ZBP*32, ZBUF.PSM, ZBUF.ZMSK);
fclose(fp);
}
};

View File

@ -0,0 +1,205 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GS.h"
__aligned(class, 32) GSDrawingEnvironment
{
public:
GIFRegPRIM PRIM;
GIFRegPRMODE PRMODE;
GIFRegPRMODECONT PRMODECONT;
GIFRegTEXCLUT TEXCLUT;
GIFRegSCANMSK SCANMSK;
GIFRegTEXA TEXA;
GIFRegFOGCOL FOGCOL;
GIFRegDIMX DIMX;
GIFRegDTHE DTHE;
GIFRegCOLCLAMP COLCLAMP;
GIFRegPABE PABE;
GIFRegBITBLTBUF BITBLTBUF;
GIFRegTRXDIR TRXDIR;
GIFRegTRXPOS TRXPOS;
GIFRegTRXREG TRXREG;
GSDrawingContext CTXT[2];
GSDrawingEnvironment()
{
}
void Reset()
{
memset(&PRIM, 0, sizeof(PRIM));
memset(&PRMODE, 0, sizeof(PRMODE));
memset(&PRMODECONT, 0, sizeof(PRMODECONT));
memset(&TEXCLUT, 0, sizeof(TEXCLUT));
memset(&SCANMSK, 0, sizeof(SCANMSK));
memset(&TEXA, 0, sizeof(TEXA));
memset(&FOGCOL, 0, sizeof(FOGCOL));
memset(&DIMX, 0, sizeof(DIMX));
memset(&DTHE, 0, sizeof(DTHE));
memset(&COLCLAMP, 0, sizeof(COLCLAMP));
memset(&PABE, 0, sizeof(PABE));
memset(&BITBLTBUF, 0, sizeof(BITBLTBUF));
memset(&TRXDIR, 0, sizeof(TRXDIR));
memset(&TRXPOS, 0, sizeof(TRXPOS));
memset(&TRXREG, 0, sizeof(TRXREG));
CTXT[0].Reset();
CTXT[1].Reset();
memset(dimx, 0, sizeof(dimx));
}
GSVector4i dimx[8];
void UpdateDIMX()
{
dimx[1] = GSVector4i(DIMX.DM00, 0, DIMX.DM01, 0, DIMX.DM02, 0, DIMX.DM03, 0);
dimx[0] = dimx[1].xxzzlh();
dimx[3] = GSVector4i(DIMX.DM10, 0, DIMX.DM11, 0, DIMX.DM12, 0, DIMX.DM13, 0),
dimx[2] = dimx[3].xxzzlh();
dimx[5] = GSVector4i(DIMX.DM20, 0, DIMX.DM21, 0, DIMX.DM22, 0, DIMX.DM23, 0),
dimx[4] = dimx[5].xxzzlh();
dimx[7] = GSVector4i(DIMX.DM30, 0, DIMX.DM31, 0, DIMX.DM32, 0, DIMX.DM33, 0),
dimx[6] = dimx[7].xxzzlh();
}
void Dump(const std::string& filename)
{
FILE* fp = fopen(filename.c_str(), "wt");
if (!fp) return;
fprintf(fp, "PRIM\n"
"\tPRIM:%d\n"
"\tIIP:%d\n"
"\tTME:%d\n"
"\tFGE:%d\n"
"\tABE:%d\n"
"\tAA1:%d\n"
"\tFST:%d\n"
"\tCTXT:%d\n"
"\tFIX:%d\n\n"
, PRIM.PRIM, PRIM.IIP, PRIM.TME, PRIM.FGE, PRIM.ABE, PRIM.AA1, PRIM.FST, PRIM.CTXT, PRIM.FIX);
fprintf(fp, "PRMODE (when AC=0)\n"
"\t_PRIM:%d\n"
"\tIIP:%d\n"
"\tTME:%d\n"
"\tFGE:%d\n"
"\tABE:%d\n"
"\tAA1:%d\n"
"\tFST:%d\n"
"\tCTXT:%d\n"
"\tFIX:%d\n\n"
, PRMODE._PRIM, PRMODE.IIP, PRMODE.TME, PRMODE.FGE, PRMODE.ABE, PRMODE.AA1, PRMODE.FST, PRMODE.CTXT, PRMODE.FIX);
fprintf(fp, "PRMODECONT\n"
"\tAC:%d\n\n"
, PRMODECONT.AC);
fprintf(fp, "TEXCLUT\n"
"\tCOU:%d\n"
"\tCBW:%d\n"
"\tCOV:%d\n\n"
, TEXCLUT.COU, TEXCLUT.CBW, TEXCLUT.COV);
fprintf(fp, "SCANMSK\n"
"\tMSK:%d\n\n"
"\n"
, SCANMSK.MSK);
fprintf(fp, "TEXA\n"
"\tAEM:%d\n"
"\tTA0:%d\n"
"\tTA1:%d\n\n"
, TEXA.AEM, TEXA.TA0, TEXA.TA1);
fprintf(fp, "FOGCOL\n"
"\tFCG:%d\n"
"\tFCB:%d\n"
"\tFCR:%d\n\n"
, FOGCOL.FCG, FOGCOL.FCB, FOGCOL.FCR);
fprintf(fp, "DIMX\n"
"\tDM22:%d\n"
"\tDM23:%d\n"
"\tDM31:%d\n"
"\tDM02:%d\n"
"\tDM21:%d\n"
"\tDM12:%d\n"
"\tDM03:%d\n"
"\tDM01:%d\n"
"\tDM33:%d\n"
"\tDM30:%d\n"
"\tDM11:%d\n"
"\tDM10:%d\n"
"\tDM20:%d\n"
"\tDM32:%d\n"
"\tDM00:%d\n"
"\tDM13:%d\n\n"
, DIMX.DM22, DIMX.DM23, DIMX.DM31, DIMX.DM02, DIMX.DM21, DIMX.DM12, DIMX.DM03, DIMX.DM01, DIMX.DM33, DIMX.DM30, DIMX.DM11, DIMX.DM10, DIMX.DM20, DIMX.DM32, DIMX.DM00, DIMX.DM13);
fprintf(fp, "DTHE\n"
"\tDTHE:%d\n\n"
, DTHE.DTHE);
fprintf(fp, "COLCLAMP\n"
"\tCLAMP:%d\n\n"
, COLCLAMP.CLAMP);
fprintf(fp, "PABE\n"
"\tPABE:%d\n\n"
, PABE.PABE);
fprintf(fp, "BITBLTBUF\n"
"\tSBW:%d\n"
"\tSBP:0x%x\n"
"\tSPSM:%d\n"
"\tDBW:%d\n"
"\tDPSM:%d\n"
"\tDBP:0x%x\n\n"
, BITBLTBUF.SBW, BITBLTBUF.SBP, BITBLTBUF.SPSM, BITBLTBUF.DBW, BITBLTBUF.DPSM, BITBLTBUF.DBP);
fprintf(fp, "TRXDIR\n"
"\tXDIR:%d\n\n"
, TRXDIR.XDIR);
fprintf(fp, "TRXPOS\n"
"\tDIRY:%d\n"
"\tSSAY:%d\n"
"\tSSAX:%d\n"
"\tDIRX:%d\n"
"\tDSAX:%d\n"
"\tDSAY:%d\n\n"
, TRXPOS.DIRY, TRXPOS.SSAY, TRXPOS.SSAX, TRXPOS.DIRX, TRXPOS.DSAX, TRXPOS.DSAY);
fprintf(fp, "TRXREG\n"
"\tRRH:%d\n"
"\tRRW:%d\n\n"
, TRXREG.RRH, TRXREG.RRW);
fclose(fp);
}
};

View File

@ -0,0 +1,95 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSDump.h"
GSDump::GSDump()
: m_gs(NULL)
, m_frames(0)
, m_extra_frames(0)
{
}
GSDump::~GSDump()
{
Close();
}
void GSDump::Open(const string& fn, uint32 crc, const GSFreezeData& fd, const GSPrivRegSet* regs)
{
m_gs = fopen((fn + ".gs").c_str(), "wb");
m_frames = 0;
m_extra_frames = 2;
if(m_gs)
{
fwrite(&crc, 4, 1, m_gs);
fwrite(&fd.size, 4, 1, m_gs);
fwrite(fd.data, fd.size, 1, m_gs);
fwrite(regs, sizeof(*regs), 1, m_gs);
}
}
void GSDump::Close()
{
if(m_gs) {fclose(m_gs); m_gs = NULL;}
}
void GSDump::Transfer(int index, const uint8* mem, size_t size)
{
if(m_gs && size > 0)
{
fputc(0, m_gs);
fputc(index, m_gs);
fwrite(&size, 4, 1, m_gs);
fwrite(mem, size, 1, m_gs);
}
}
void GSDump::ReadFIFO(uint32 size)
{
if(m_gs && size > 0)
{
fputc(2, m_gs);
fwrite(&size, 4, 1, m_gs);
}
}
void GSDump::VSync(int field, bool last, const GSPrivRegSet* regs)
{
if(m_gs)
{
fputc(3, m_gs);
fwrite(regs, sizeof(*regs), 1, m_gs);
fputc(1, m_gs);
fputc(field, m_gs);
if((++m_frames & 1) == 0 && last && (m_extra_frames <= 0))
{
Close();
} else if (last) {
m_extra_frames--;
}
}
}

View File

@ -0,0 +1,62 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GS.h"
#include "GSVertexSW.h"
/*
Dump file format:
- [crc/4] [state size/4] [state data/size] [PMODE/0x2000] [id/1] [data/?] .. [id/1] [data/?]
Transfer data (id == 0)
- [0/1] [path index/1] [size/4] [data/size]
VSync data (id == 1)
- [1/1] [field/1]
ReadFIFO2 data (id == 2)
- [2/1] [size/?]
Regs data (id == 3)
- [PMODE/0x2000]
*/
class GSDump
{
FILE* m_gs;
int m_frames;
int m_extra_frames;
public:
GSDump();
virtual ~GSDump();
void Open(const string& fn, uint32 crc, const GSFreezeData& fd, const GSPrivRegSet* regs);
void Close();
void ReadFIFO(uint32 size);
void Transfer(int index, const uint8* mem, size_t size);
void VSync(int field, bool last, const GSPrivRegSet* regs);
operator bool() {return m_gs != NULL;}
};

View File

@ -0,0 +1,23 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSFunctionMap.h"

View File

@ -0,0 +1,241 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GS.h"
#include "GSCodeBuffer.h"
#include "xbyak/xbyak.h"
#include "xbyak/xbyak_util.h"
template<class KEY, class VALUE> class GSFunctionMap
{
protected:
struct ActivePtr
{
uint64 frame, frames;
uint64 ticks, actual, total;
VALUE f;
};
hash_map<KEY, VALUE> m_map;
hash_map<KEY, ActivePtr*> m_map_active;
ActivePtr* m_active;
virtual VALUE GetDefaultFunction(KEY key) = 0;
public:
GSFunctionMap()
: m_active(NULL)
{
}
virtual ~GSFunctionMap()
{
for_each(m_map_active.begin(), m_map_active.end(), delete_second());
}
VALUE operator [] (KEY key)
{
m_active = NULL;
typename hash_map<KEY, ActivePtr*>::iterator i = m_map_active.find(key);
if(i != m_map_active.end())
{
m_active = i->second;
}
else
{
typename hash_map<KEY, VALUE>::iterator i = m_map.find(key);
ActivePtr* p = new ActivePtr();
memset(p, 0, sizeof(*p));
p->frame = (uint64)-1;
p->f = i != m_map.end() ? i->second : GetDefaultFunction(key);
m_map_active[key] = p;
m_active = p;
}
return m_active->f;
}
void UpdateStats(uint64 frame, uint64 ticks, int actual, int total)
{
if(m_active)
{
if(m_active->frame != frame)
{
m_active->frame = frame;
m_active->frames++;
}
m_active->ticks += ticks;
m_active->actual += actual;
m_active->total += total;
ASSERT(m_active->total >= m_active->actual);
}
}
virtual void PrintStats()
{
uint64 ttpf = 0;
typename hash_map<KEY, ActivePtr*>::iterator i;
for(i = m_map_active.begin(); i != m_map_active.end(); i++)
{
ActivePtr* p = i->second;
if(p->frames)
{
ttpf += p->ticks / p->frames;
}
}
printf("GS stats\n");
for(i = m_map_active.begin(); i != m_map_active.end(); i++)
{
KEY key = i->first;
ActivePtr* p = i->second;
if(p->frames && ttpf)
{
uint64 tpp = p->actual > 0 ? p->ticks / p->actual : 0;
uint64 tpf = p->frames > 0 ? p->ticks / p->frames : 0;
uint64 ppf = p->frames > 0 ? p->actual / p->frames : 0;
printf("[%014llx]%c %6.2f%% %5.2f%% f %4lld t %12lld p %12lld w %12lld tpp %4lld tpf %9lld ppf %9lld\n",
(uint64)key, m_map.find(key) == m_map.end() ? '*' : ' ',
(float)(tpf * 10000 / 34000000) / 100,
(float)(tpf * 10000 / ttpf) / 100,
p->frames, p->ticks, p->actual, p->total - p->actual,
tpp, tpf, ppf);
}
}
}
};
class GSCodeGenerator : public Xbyak::CodeGenerator
{
protected:
Xbyak::util::Cpu m_cpu;
public:
GSCodeGenerator(void* code, size_t maxsize)
: Xbyak::CodeGenerator(maxsize, code)
{
}
};
template<class CG, class KEY, class VALUE>
class GSCodeGeneratorFunctionMap : public GSFunctionMap<KEY, VALUE>
{
string m_name;
void* m_param;
hash_map<uint64, VALUE> m_cgmap;
GSCodeBuffer m_cb;
enum {MAX_SIZE = 8192};
public:
GSCodeGeneratorFunctionMap(const char* name, void* param)
: m_name(name)
, m_param(param)
{
}
VALUE GetDefaultFunction(KEY key)
{
VALUE ret = NULL;
typename hash_map<uint64, VALUE>::iterator i = m_cgmap.find(key);
if(i != m_cgmap.end())
{
ret = i->second;
}
else
{
CG* cg = new CG(m_param, key, m_cb.GetBuffer(MAX_SIZE), MAX_SIZE);
ASSERT(cg->getSize() < MAX_SIZE);
m_cb.ReleaseBuffer(cg->getSize());
ret = (VALUE)cg->getCode();
m_cgmap[key] = ret;
#ifdef ENABLE_VTUNE
// vtune method registration
// if(iJIT_IsProfilingActive()) // always > 0
{
string name = format("%s<%016llx>()", m_name.c_str(), (uint64)key);
iJIT_Method_Load ml;
memset(&ml, 0, sizeof(ml));
ml.method_id = iJIT_GetNewMethodID();
ml.method_name = (char*)name.c_str();
ml.method_load_address = (void*)cg->getCode();
ml.method_size = (unsigned int)cg->getSize();
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &ml);
/*
name = format("c:/temp1/%s_%016llx.bin", m_name.c_str(), (uint64)key);
if(FILE* fp = fopen(name.c_str(), "wb"))
{
fputc(0x0F, fp); fputc(0x0B, fp);
fputc(0xBB, fp); fputc(0x6F, fp); fputc(0x00, fp); fputc(0x00, fp); fputc(0x00, fp);
fputc(0x64, fp); fputc(0x67, fp); fputc(0x90, fp);
fwrite(cg->getCode(), cg->getSize(), 1, fp);
fputc(0xBB, fp); fputc(0xDE, fp); fputc(0x00, fp); fputc(0x00, fp); fputc(0x00, fp);
fputc(0x64, fp); fputc(0x67, fp); fputc(0x90, fp);
fputc(0x0F, fp); fputc(0x0B, fp);
fclose(fp);
}
*/
}
#endif
delete cg;
}
return ret;
}
};

View File

@ -0,0 +1,520 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include <gtk/gtk.h>
#include "GS.h"
#include "GSdx.h"
#include "GSLinuxLogo.h"
#include "GSSetting.h"
void AddTooltip(GtkWidget* w, int idc)
{
gtk_widget_set_tooltip_text(w, dialog_message(idc));
}
void AddTooltip(GtkWidget* w1, GtkWidget* w2, int idc)
{
AddTooltip(w1, idc);
AddTooltip(w2, idc);
}
GtkWidget* left_label(const char* lbl)
{
GtkWidget* w = gtk_label_new(lbl);
#if GTK_MAJOR_VERSION >= 3
gtk_widget_set_halign(w, GTK_ALIGN_START);
#else
gtk_misc_set_alignment(GTK_MISC(w),0.0,0.5);
#endif
return w;
}
void CB_ChangedComboBox(GtkComboBox *combo, gpointer user_data)
{
int p = gtk_combo_box_get_active(combo);
vector<GSSetting>* s = (vector<GSSetting>*)g_object_get_data(G_OBJECT(combo), "Settings");
try {
theApp.SetConfig((char*)user_data, s->at(p).value);
} catch (...) {
}
}
GtkWidget* CreateComboBoxFromVector(const vector<GSSetting>& s, const char* opt_name, int32_t opt_default = 0)
{
GtkWidget* combo_box = gtk_combo_box_text_new();
int32_t opt_value = theApp.GetConfig(opt_name, opt_default);
int opt_position = 0;
for(size_t i = 0; i < s.size(); i++)
{
string label = s[i].name;
if(!s[i].note.empty()) label += format(" (%s)", s[i].note.c_str());
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_box), label.c_str());
if (s[i].value == opt_value)
opt_position = i;
}
gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), opt_position);
g_signal_connect(combo_box, "changed", G_CALLBACK(CB_ChangedComboBox), const_cast<char*>(opt_name));
g_object_set_data(G_OBJECT(combo_box), "Settings", (void*)&s);
return combo_box;
}
void CB_PreEntryActived(GtkEntry *entry, gchar* preedit, gpointer user_data)
{
int hex_value = 0;
sscanf(preedit,"%X",&hex_value);
theApp.SetConfig((char*)user_data, hex_value);
}
void CB_EntryActived(GtkEntry *entry, gpointer user_data)
{
int hex_value = 0;
const gchar *data = gtk_entry_get_text(entry);
sscanf(data,"%X",&hex_value);
theApp.SetConfig((char*)user_data, hex_value);
}
GtkWidget* CreateTextBox(const char* opt_name, int opt_default = 0) {
GtkWidget* entry = gtk_entry_new();
int hex_value = theApp.GetConfig(opt_name, opt_default);
gchar* data=(gchar *)g_malloc(sizeof(gchar)*40);
sprintf(data,"%X", hex_value);
gtk_entry_set_text(GTK_ENTRY(entry),data);
g_free(data);
g_signal_connect(entry, "activate", G_CALLBACK(CB_EntryActived), const_cast<char*>(opt_name));
// Note it doesn't seem to work as expected
g_signal_connect(entry, "preedit-changed", G_CALLBACK(CB_PreEntryActived), const_cast<char*>(opt_name));
return entry;
}
void CB_ToggleCheckBox(GtkToggleButton *togglebutton, gpointer user_data)
{
theApp.SetConfig((char*)user_data, (int)gtk_toggle_button_get_active(togglebutton));
}
GtkWidget* CreateCheckBox(const char* label, const char* opt_name, bool opt_default = false)
{
GtkWidget* check = gtk_check_button_new_with_label(label);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), theApp.GetConfig(opt_name, opt_default));
g_signal_connect(check, "toggled", G_CALLBACK(CB_ToggleCheckBox), const_cast<char*>(opt_name));
return check;
}
void CB_SpinButton(GtkSpinButton *spin, gpointer user_data)
{
theApp.SetConfig((char*)user_data, (int)gtk_spin_button_get_value(spin));
}
GtkWidget* CreateSpinButton(double min, double max, const char* opt_name, int opt_default = 0)
{
GtkWidget* spin = gtk_spin_button_new_with_range(min, max, 1);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), theApp.GetConfig(opt_name, opt_default));
g_signal_connect(spin, "value-changed", G_CALLBACK(CB_SpinButton), const_cast<char*>(opt_name));
return spin;
}
void CB_RangeChanged(GtkRange* range, gpointer user_data)
{
theApp.SetConfig((char*)user_data, (int)gtk_range_get_value(range));
}
GtkWidget* CreateScale(const char* opt_name, int opt_default = 0)
{
#if GTK_MAJOR_VERSION < 3
GtkWidget* scale = gtk_hscale_new_with_range(0, 200, 10);
#else
GtkWidget* scale = gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL, 0, 200, 10);
#endif
gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_RIGHT);
gtk_range_set_value(GTK_RANGE(scale), theApp.GetConfig(opt_name, opt_default));
g_signal_connect(scale, "value-changed", G_CALLBACK(CB_RangeChanged), const_cast<char*>(opt_name));
return scale;
}
void CB_PickFile(GtkFileChooserButton *chooser, gpointer user_data)
{
theApp.SetConfig((char*)user_data, gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(chooser)));
}
GtkWidget* CreateFileChooser(GtkFileChooserAction action, const char* label, const char* opt_name, const char* opt_default)
{
GtkWidget* chooser = gtk_file_chooser_button_new(label, action);
gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(chooser), theApp.GetConfig(opt_name, opt_default).c_str());
g_signal_connect(chooser, "file-set", G_CALLBACK(CB_PickFile), const_cast<char*>(opt_name));
return chooser;
}
static int s_table_line = 0;
static void InsertWidgetInTable(GtkWidget* table, GtkWidget *left, GtkWidget *right = NULL, GtkWidget *third = NULL) {
GtkAttachOptions opt = (GtkAttachOptions)(GTK_EXPAND | GTK_FILL); // default
guint l_xpad = GTK_IS_CHECK_BUTTON(left) ? 0 : 22;
guint r_xpad = 0;
guint ypad = 0;
if (!left) {
gtk_table_attach(GTK_TABLE(table), right, 1, 2, s_table_line, s_table_line+1, opt, opt, r_xpad, ypad);
} else if (!right) {
gtk_table_attach(GTK_TABLE(table), left, 0, 1, s_table_line, s_table_line+1, opt, opt, l_xpad, ypad);
} else if (right == left) {
gtk_table_attach(GTK_TABLE(table), left, 0, 2, s_table_line, s_table_line+1, opt, opt, r_xpad, ypad);
} else {
gtk_table_attach(GTK_TABLE(table), left, 0, 1, s_table_line, s_table_line+1, opt, opt, l_xpad, ypad);
gtk_table_attach(GTK_TABLE(table), right, 1, 2, s_table_line, s_table_line+1, opt, opt, r_xpad, ypad);
}
if (third) {
gtk_table_attach(GTK_TABLE(table), third, 2, 3, s_table_line, s_table_line+1, opt, opt, r_xpad, ypad);
}
s_table_line++;
}
GtkWidget* CreateTableInBox(GtkWidget* parent_box, const char* frame_title, int row, int col) {
GtkWidget* table = gtk_table_new(row, col, false);
GtkWidget* container = (frame_title) ? gtk_frame_new (frame_title) : gtk_vbox_new(false, 5);
gtk_container_add(GTK_CONTAINER(container), table);
gtk_container_add(GTK_CONTAINER(parent_box), container);
return table;
}
void populate_hw_table(GtkWidget* hw_table)
{
GtkWidget* filter_label = left_label("Texture Filtering:");
GtkWidget* filter_combo_box = CreateComboBoxFromVector(theApp.m_gs_filter, "filter", 2);
GtkWidget* fsaa_label = left_label("Internal Resolution:");
GtkWidget* fsaa_combo_box = CreateComboBoxFromVector(theApp.m_gs_upscale_multiplier, "upscale_multiplier", 1);
GtkWidget* af_label = left_label("Anisotropic Filtering:");
GtkWidget* af_combo_box = CreateComboBoxFromVector(theApp.m_gs_max_anisotropy, "MaxAnisotropy", 0);
GtkWidget* crc_label = left_label("Automatic CRC level:");
GtkWidget* crc_combo_box = CreateComboBoxFromVector(theApp.m_gs_crc_level, "crc_hack_level", 3);
GtkWidget* paltex_check = CreateCheckBox("Allow 8 bits textures", "paltex");
GtkWidget* acc_date_check = CreateCheckBox("Accurate Date", "accurate_date", false);
GtkWidget* tc_depth_check = CreateCheckBox("Full Depth Emulation", "texture_cache_depth", true);
GtkWidget* acc_bld_label = left_label("Blending Unit Accuracy:");
GtkWidget* acc_bld_combo_box = CreateComboBoxFromVector(theApp.m_gs_acc_blend_level, "accurate_blending_unit", 1);
// Some helper string
AddTooltip(paltex_check, IDC_PALTEX);
AddTooltip(acc_date_check, IDC_ACCURATE_DATE);
AddTooltip(crc_label, crc_combo_box, IDC_CRC_LEVEL);
AddTooltip(acc_bld_label, acc_bld_combo_box, IDC_ACCURATE_BLEND_UNIT);
AddTooltip(tc_depth_check, IDC_TC_DEPTH);
AddTooltip(filter_label, filter_combo_box, IDC_FILTER);
AddTooltip(af_label, af_combo_box, IDC_AFCOMBO);
s_table_line = 0;
InsertWidgetInTable(hw_table, paltex_check, tc_depth_check);
InsertWidgetInTable(hw_table, acc_date_check);
InsertWidgetInTable(hw_table, fsaa_label, fsaa_combo_box);
InsertWidgetInTable(hw_table, filter_label, filter_combo_box);
InsertWidgetInTable(hw_table, af_label, af_combo_box);
InsertWidgetInTable(hw_table, acc_bld_label, acc_bld_combo_box);
InsertWidgetInTable(hw_table, crc_label, crc_combo_box);
}
void populate_gl_table(GtkWidget* gl_table)
{
GtkWidget* gl_bs_label = left_label("Buffer Storage:");
GtkWidget* gl_bs_combo = CreateComboBoxFromVector(theApp.m_gs_gl_ext, "override_GL_ARB_buffer_storage", -1);
GtkWidget* gl_sso_label = left_label("Separate Shader:");
GtkWidget* gl_sso_combo = CreateComboBoxFromVector(theApp.m_gs_gl_ext, "override_GL_ARB_separate_shader_objects", -1);
GtkWidget* gl_gs_label = left_label("Geometry Shader:");
GtkWidget* gl_gs_combo = CreateComboBoxFromVector(theApp.m_gs_gl_ext, "override_geometry_shader", -1);
GtkWidget* gl_ils_label = left_label("Image Load Store:");
GtkWidget* gl_ils_combo = CreateComboBoxFromVector(theApp.m_gs_gl_ext, "override_GL_ARB_shader_image_load_store", -1);
GtkWidget* gl_cc_label = left_label("Clip Control (depth accuracy):");
GtkWidget* gl_cc_combo = CreateComboBoxFromVector(theApp.m_gs_gl_ext, "override_GL_ARB_clip_control", -1);
GtkWidget* gl_tb_label = left_label("Texture Barrier:");
GtkWidget* gl_tb_combo = CreateComboBoxFromVector(theApp.m_gs_gl_ext, "override_GL_ARB_texture_barrier", -1);
s_table_line = 0;
InsertWidgetInTable(gl_table , gl_gs_label , gl_gs_combo);
InsertWidgetInTable(gl_table , gl_bs_label , gl_bs_combo);
InsertWidgetInTable(gl_table , gl_sso_label , gl_sso_combo);
InsertWidgetInTable(gl_table , gl_ils_label , gl_ils_combo);
InsertWidgetInTable(gl_table , gl_cc_label , gl_cc_combo);
InsertWidgetInTable(gl_table , gl_tb_label , gl_tb_combo);
}
void populate_sw_table(GtkWidget* sw_table)
{
GtkWidget* threads_label = left_label("Extra rendering threads:");
GtkWidget* threads_spin = CreateSpinButton(0, 32, "extrathreads", DEFAULT_EXTRA_RENDERING_THREADS);
GtkWidget* aa_check = CreateCheckBox("Edge anti-aliasing (AA1)", "aa1");
GtkWidget* mipmap_check = CreateCheckBox("Mipmap", "mipmap", true);
AddTooltip(aa_check, IDC_AA1);
AddTooltip(mipmap_check, IDC_MIPMAP);
AddTooltip(threads_label, threads_spin, IDC_SWTHREADS);
s_table_line = 0;
InsertWidgetInTable(sw_table , threads_label , threads_spin);
InsertWidgetInTable(sw_table , aa_check, mipmap_check);
}
void populate_shader_table(GtkWidget* shader_table)
{
GtkWidget* shader = CreateFileChooser(GTK_FILE_CHOOSER_ACTION_OPEN, "Select an external shader", "shaderfx_glsl", "dummy.glsl");
GtkWidget* shader_conf = CreateFileChooser(GTK_FILE_CHOOSER_ACTION_OPEN, "Then select a config", "shaderfx_conf", "dummy.ini");
GtkWidget* shader_label = left_label("External shader glsl");
GtkWidget* shader_conf_label = left_label("External shader conf");
GtkWidget* shadeboost_check = CreateCheckBox("Shade boost", "ShadeBoost");
GtkWidget* fxaa_check = CreateCheckBox("Fxaa shader", "fxaa");
GtkWidget* shaderfx_check = CreateCheckBox("External shader", "shaderfx");
GtkWidget* tv_shader_label = left_label("TV shader:");
GtkWidget* tv_shader = CreateComboBoxFromVector(theApp.m_gs_tv_shaders, "TVShader");
// Shadeboost scale
GtkWidget* sb_brightness = CreateScale("ShadeBoost_Brightness", 50);
GtkWidget* sb_brightness_label = left_label("Shade Boost Brightness:");
GtkWidget* sb_contrast = CreateScale("ShadeBoost_Contrast", 50);
GtkWidget* sb_contrast_label = left_label("Shade Boost Contrast:");
GtkWidget* sb_saturation = CreateScale("ShadeBoost_Saturation", 50);
GtkWidget* sb_saturation_label = left_label("Shade Boost Saturation:");
AddTooltip(shadeboost_check, IDC_SHADEBOOST);
AddTooltip(shaderfx_check, IDC_SHADER_FX);
AddTooltip(fxaa_check, IDC_FXAA);
s_table_line = 0;
InsertWidgetInTable(shader_table , fxaa_check);
InsertWidgetInTable(shader_table , shadeboost_check);
InsertWidgetInTable(shader_table , sb_brightness_label , sb_brightness);
InsertWidgetInTable(shader_table , sb_contrast_label , sb_contrast);
InsertWidgetInTable(shader_table , sb_saturation_label , sb_saturation);
InsertWidgetInTable(shader_table , shaderfx_check);
InsertWidgetInTable(shader_table , shader_label , shader);
InsertWidgetInTable(shader_table , shader_conf_label , shader_conf);
InsertWidgetInTable(shader_table , tv_shader_label, tv_shader);
}
void populate_hack_table(GtkWidget* hack_table)
{
GtkWidget* hack_offset_check = CreateCheckBox("Half-pixel Offset Hack", "UserHacks_HalfPixelOffset");
GtkWidget* hack_skipdraw_label = left_label("Skipdraw:");
GtkWidget* hack_skipdraw_spin = CreateSpinButton(0, 1000, "UserHacks_SkipDraw");
GtkWidget* hack_enble_check = CreateCheckBox("Enable User Hacks", "UserHacks");
GtkWidget* hack_wild_check = CreateCheckBox("Wild Arms Hack", "UserHacks_WildHack");
GtkWidget* hack_tco_label = left_label("Texture Offset: 0x");
GtkWidget* hack_tco_entry = CreateTextBox("UserHacks_TCOffset");
GtkWidget* align_sprite_check = CreateCheckBox("Align sprite hack", "UserHacks_align_sprite_X");
GtkWidget* preload_gs_check = CreateCheckBox("Preload Frame", "preload_frame_with_gs_data");
GtkWidget* hack_safe_fbmask = CreateCheckBox("Safe Accurate Blending", "UserHacks_safe_fbmask");
GtkWidget* hack_fast_inv = CreateCheckBox("Fast Texture Invalidation", "UserHacks_DisablePartialInvalidation");
GtkWidget* hack_sprite_box = CreateComboBoxFromVector(theApp.m_gs_hack, "UserHacks_SpriteHack");
GtkWidget* hack_sprite_label = left_label("Alpha-Sprite Hack:");
GtkWidget* stretch_hack_box = CreateComboBoxFromVector(theApp.m_gs_hack, "UserHacks_round_sprite_offset");
GtkWidget* stretch_hack_label = left_label("Align Sprite Texture:");
// Reuse windows helper string :)
AddTooltip(hack_offset_check, IDC_OFFSETHACK);
AddTooltip(hack_skipdraw_label, IDC_SKIPDRAWHACK);
AddTooltip(hack_skipdraw_spin, IDC_SKIPDRAWHACK);
gtk_widget_set_tooltip_text(hack_enble_check, "Allows the use of the hack below");
AddTooltip(hack_wild_check, IDC_WILDHACK);
AddTooltip(hack_sprite_label, hack_sprite_box, IDC_SPRITEHACK);
AddTooltip(hack_tco_label, IDC_TCOFFSETX);
AddTooltip(hack_tco_entry, IDC_TCOFFSETX);
AddTooltip(align_sprite_check, IDC_ALIGN_SPRITE);
AddTooltip(stretch_hack_label, stretch_hack_box, IDC_ROUND_SPRITE);
AddTooltip(preload_gs_check, IDC_PRELOAD_GS);
AddTooltip(hack_safe_fbmask, IDC_SAFE_FBMASK);
AddTooltip(hack_fast_inv, IDC_FAST_TC_INV);
s_table_line = 0;
InsertWidgetInTable(hack_table , hack_enble_check);
InsertWidgetInTable(hack_table , hack_wild_check , align_sprite_check);
InsertWidgetInTable(hack_table , hack_offset_check , preload_gs_check);
InsertWidgetInTable(hack_table , hack_safe_fbmask , hack_fast_inv);
InsertWidgetInTable(hack_table , hack_sprite_label , hack_sprite_box );
InsertWidgetInTable(hack_table , stretch_hack_label , stretch_hack_box );
InsertWidgetInTable(hack_table , hack_skipdraw_label , hack_skipdraw_spin);
InsertWidgetInTable(hack_table , hack_tco_label , hack_tco_entry);
}
void populate_main_table(GtkWidget* main_table)
{
GtkWidget* render_label = left_label("Renderer:");
GtkWidget* render_combo_box = CreateComboBoxFromVector(theApp.m_gs_renderers, "Renderer", static_cast<int>(GSRendererType::Default));
GtkWidget* interlace_label = left_label("Interlacing (F5):");
GtkWidget* interlace_combo_box = CreateComboBoxFromVector(theApp.m_gs_interlace, "interlace", 7);
s_table_line = 0;
InsertWidgetInTable(main_table, render_label, render_combo_box);
InsertWidgetInTable(main_table, interlace_label, interlace_combo_box);
}
void populate_debug_table(GtkWidget* debug_table)
{
GtkWidget* glsl_debug_check = CreateCheckBox("GLSL compilation", "debug_glsl_shader");
GtkWidget* gl_debug_check = CreateCheckBox("Print GL error", "debug_opengl");
GtkWidget* gs_dump_check = CreateCheckBox("Dump GS data", "dump");
GtkWidget* gs_save_check = CreateCheckBox("Save RT", "save");
GtkWidget* gs_savef_check = CreateCheckBox("Save Frame", "savef");
GtkWidget* gs_savet_check = CreateCheckBox("Save Texture", "savet");
GtkWidget* gs_savez_check = CreateCheckBox("Save Depth", "savez");
GtkWidget* gs_saven_label = left_label("Start of Dump");
GtkWidget* gs_saven_spin = CreateSpinButton(0, pow(10, 9), "saven");
GtkWidget* gs_savel_label = left_label("Length of Dump");
GtkWidget* gs_savel_spin = CreateSpinButton(0, pow(10, 5), "savel");
s_table_line = 0;
InsertWidgetInTable(debug_table, gl_debug_check, glsl_debug_check);
InsertWidgetInTable(debug_table, gs_dump_check);
InsertWidgetInTable(debug_table, gs_save_check, gs_savef_check);
InsertWidgetInTable(debug_table, gs_savet_check, gs_savez_check);
InsertWidgetInTable(debug_table, gs_saven_label, gs_saven_spin);
InsertWidgetInTable(debug_table, gs_savel_label, gs_savel_spin);
}
void populate_record_table(GtkWidget* record_table)
{
GtkWidget* capture_check = CreateCheckBox("Enable Recording (with F12)", "capture_enabled");
GtkWidget* resxy_label = left_label("Resolution:");
GtkWidget* resx_spin = CreateSpinButton(256, 8192, "capture_resx", 1280);
GtkWidget* resy_spin = CreateSpinButton(256, 8192, "capture_resy", 1024);
GtkWidget* threads_label = left_label("Saving Threads:");
GtkWidget* threads_spin = CreateSpinButton(1, 32, "capture_threads", 4);
GtkWidget* out_dir_label = left_label("Output Directory:");
GtkWidget* out_dir = CreateFileChooser(GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, "Select a directory", "capture_out_dir", "/tmp");
GtkWidget* png_label = left_label("PNG Compression Level:");
GtkWidget* png_level = CreateSpinButton(1, 9, "png_compression_level", 1);
InsertWidgetInTable(record_table , capture_check);
InsertWidgetInTable(record_table , resxy_label , resx_spin , resy_spin);
InsertWidgetInTable(record_table , threads_label , threads_spin);
InsertWidgetInTable(record_table , png_label , png_level);
InsertWidgetInTable(record_table , out_dir_label , out_dir);
}
bool RunLinuxDialog()
{
GtkWidget *dialog;
int return_value;
/* Create the widgets */
dialog = gtk_dialog_new_with_buttons (
"GSdx Config",
NULL, /* parent window*/
(GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
"OK", GTK_RESPONSE_ACCEPT,
// "Cancel", GTK_RESPONSE_REJECT, // Drop because it is too annoying to support call back this way
NULL);
// The main area for the whole dialog box.
GtkWidget* main_box = gtk_vbox_new(false, 5);
GtkWidget* central_box = gtk_vbox_new(false, 5);
GtkWidget* advanced_box = gtk_vbox_new(false, 5);
GtkWidget* debug_box = gtk_vbox_new(false, 5);
// Grab a logo, to make things look nice.
GdkPixbuf* logo_pixmap = gdk_pixbuf_from_pixdata(&gsdx_ogl_logo, false, NULL);
GtkWidget* logo_image = gtk_image_new_from_pixbuf(logo_pixmap);
gtk_box_pack_start(GTK_BOX(main_box), logo_image, true, true, 0);
GtkWidget* main_table = CreateTableInBox(main_box , NULL , 2 , 2);
GtkWidget* shader_table = CreateTableInBox(central_box , "Custom Shader Settings" , 9 , 2);
GtkWidget* hw_table = CreateTableInBox(central_box , "Hardware Mode Settings" , 7 , 2);
GtkWidget* sw_table = CreateTableInBox(central_box , "Software Mode Settings" , 2 , 2);
GtkWidget* hack_table = CreateTableInBox(advanced_box, "Hacks" , 7 , 2);
GtkWidget* gl_table = CreateTableInBox(advanced_box, "OpenGL Very Advanced Custom Settings" , 6 , 2);
GtkWidget* record_table = CreateTableInBox(debug_box , "Recording Settings" , 4 , 3);
GtkWidget* debug_table = CreateTableInBox(debug_box , "OpenGL / GSdx Debug Settings" , 6 , 3);
// Populate all the tables
populate_main_table(main_table);
populate_shader_table(shader_table);
populate_hw_table(hw_table);
populate_sw_table(sw_table);
populate_hack_table(hack_table);
populate_gl_table(gl_table);
populate_debug_table(debug_table);
populate_record_table(record_table);
// Handle some nice tab
GtkWidget* notebook = gtk_notebook_new();
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), central_box , gtk_label_new("Global Settings"));
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), advanced_box, gtk_label_new("Advanced Settings"));
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), debug_box , gtk_label_new("Debug/Recording Settings"));
// Put everything in the big box.
gtk_container_add(GTK_CONTAINER(main_box), notebook);
// 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);
return_value = gtk_dialog_run (GTK_DIALOG (dialog));
// Compatibility & not supported option
int mode_width = theApp.GetConfig("ModeWidth", 640);
int mode_height = theApp.GetConfig("ModeHeight", 480);
theApp.SetConfig("ModeHeight", mode_height);
theApp.SetConfig("ModeWidth", mode_width);
theApp.SetConfig("msaa", 0);
theApp.SetConfig("windowed", 1);
gtk_widget_destroy (dialog);
return (return_value == GTK_RESPONSE_ACCEPT);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,918 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GS.h"
#include "GSTables.h"
#include "GSVector.h"
#include "GSBlock.h"
#include "GSClut.h"
class GSOffset : public GSAlignedClass<32>
{
public:
__aligned(struct, 32) Block
{
short row[256]; // yn (n = 0 8 16 ...)
short* col; // blockOffset*
};
__aligned(struct, 32) Pixel
{
int row[4096]; // yn (n = 0 1 2 ...) NOTE: this wraps around above 2048, only transfers should address the upper half (dark cloud 2 inventing)
int* col[8]; // rowOffset*
};
union {uint32 hash; struct {uint32 bp:14, bw:6, psm:6;};};
Block block;
Pixel pixel;
GSOffset(uint32 bp, uint32 bw, uint32 psm);
virtual ~GSOffset();
enum {EOP = 0xffffffff};
uint32* GetPages(const GSVector4i& rect, uint32* pages = NULL, GSVector4i* bbox = NULL);
GSVector4i* GetPagesAsBits(const GSVector4i& rect, GSVector4i* pages = NULL, GSVector4i* bbox = NULL); // free returned value with _aligned_free
};
struct GSPixelOffset
{
// 16 bit offsets (m_vm16[...])
GSVector2i row[2048]; // f yn | z yn
GSVector2i col[2048]; // f xn | z xn
uint32 hash;
uint32 fbp, zbp, fpsm, zpsm, bw;
};
struct GSPixelOffset4
{
// 16 bit offsets (m_vm16[...])
GSVector2i row[2048]; // f yn | z yn (n = 0 1 2 ...)
GSVector2i col[512]; // f xn | z xn (n = 0 4 8 ...)
uint32 hash;
uint32 fbp, zbp, fpsm, zpsm, bw;
};
class GSLocalMemory : public GSAlignedClass<32>
{
public:
typedef uint32 (*pixelAddress)(int x, int y, uint32 bp, uint32 bw);
typedef void (GSLocalMemory::*writePixel)(int x, int y, uint32 c, uint32 bp, uint32 bw);
typedef void (GSLocalMemory::*writeFrame)(int x, int y, uint32 c, uint32 bp, uint32 bw);
typedef uint32 (GSLocalMemory::*readPixel)(int x, int y, uint32 bp, uint32 bw) const;
typedef uint32 (GSLocalMemory::*readTexel)(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const;
typedef void (GSLocalMemory::*writePixelAddr)(uint32 addr, uint32 c);
typedef void (GSLocalMemory::*writeFrameAddr)(uint32 addr, uint32 c);
typedef uint32 (GSLocalMemory::*readPixelAddr)(uint32 addr) const;
typedef uint32 (GSLocalMemory::*readTexelAddr)(uint32 addr, const GIFRegTEXA& TEXA) const;
typedef void (GSLocalMemory::*writeImage)(int& tx, int& ty, const uint8* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG);
typedef void (GSLocalMemory::*readImage)(int& tx, int& ty, uint8* dst, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) const;
typedef void (GSLocalMemory::*readTexture)(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
typedef void (GSLocalMemory::*readTextureBlock)(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const;
__aligned(struct, 128) psm_t
{
pixelAddress pa, bn;
readPixel rp;
readPixelAddr rpa;
writePixel wp;
writePixelAddr wpa;
readTexel rt;
readTexelAddr rta;
writeFrameAddr wfa;
writeImage wi;
readImage ri;
readTexture rtx, rtxP;
readTextureBlock rtxb, rtxbP;
uint16 bpp, trbpp, pal, fmt;
GSVector2i bs, pgs;
int* rowOffset[8];
short* blockOffset;
uint8 msk;
};
static psm_t m_psm[64];
static const int m_vmsize = 1024 * 1024 * 4;
uint8* m_vm8;
uint16* m_vm16;
uint32* m_vm32;
GSClut m_clut;
protected:
static uint32 pageOffset32[32][32][64];
static uint32 pageOffset32Z[32][32][64];
static uint32 pageOffset16[32][64][64];
static uint32 pageOffset16S[32][64][64];
static uint32 pageOffset16Z[32][64][64];
static uint32 pageOffset16SZ[32][64][64];
static uint32 pageOffset8[32][64][128];
static uint32 pageOffset4[32][128][128];
static int rowOffset32[4096];
static int rowOffset32Z[4096];
static int rowOffset16[4096];
static int rowOffset16S[4096];
static int rowOffset16Z[4096];
static int rowOffset16SZ[4096];
static int rowOffset8[2][4096];
static int rowOffset4[2][4096];
static short blockOffset32[256];
static short blockOffset32Z[256];
static short blockOffset16[256];
static short blockOffset16S[256];
static short blockOffset16Z[256];
static short blockOffset16SZ[256];
static short blockOffset8[256];
static short blockOffset4[256];
__forceinline static uint32 Expand24To32(uint32 c, const GIFRegTEXA& TEXA)
{
return (((!TEXA.AEM | (c & 0xffffff)) ? TEXA.TA0 : 0) << 24) | (c & 0xffffff);
}
__forceinline static uint32 Expand16To32(uint16 c, const GIFRegTEXA& TEXA)
{
return (((c & 0x8000) ? TEXA.TA1 : (!TEXA.AEM | c) ? TEXA.TA0 : 0) << 24) | ((c & 0x7c00) << 9) | ((c & 0x03e0) << 6) | ((c & 0x001f) << 3);
}
// TODO
friend class GSClut;
//
hash_map<uint32, GSOffset*> m_omap;
hash_map<uint32, GSPixelOffset*> m_pomap;
hash_map<uint32, GSPixelOffset4*> m_po4map;
hash_map<uint64, vector<GSVector2i>*> m_p2tmap;
public:
GSLocalMemory();
virtual ~GSLocalMemory();
GSOffset* GetOffset(uint32 bp, uint32 bw, uint32 psm);
GSPixelOffset* GetPixelOffset(const GIFRegFRAME& FRAME, const GIFRegZBUF& ZBUF);
GSPixelOffset4* GetPixelOffset4(const GIFRegFRAME& FRAME, const GIFRegZBUF& ZBUF);
vector<GSVector2i>* GetPage2TileMap(const GIFRegTEX0& TEX0);
// address
static uint32 BlockNumber32(int x, int y, uint32 bp, uint32 bw)
{
return bp + (y & ~0x1f) * bw + ((x >> 1) & ~0x1f) + blockTable32[(y >> 3) & 3][(x >> 3) & 7];
}
static uint32 BlockNumber16(int x, int y, uint32 bp, uint32 bw)
{
return bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f) + blockTable16[(y >> 3) & 7][(x >> 4) & 3];
}
static uint32 BlockNumber16S(int x, int y, uint32 bp, uint32 bw)
{
return bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f) + blockTable16S[(y >> 3) & 7][(x >> 4) & 3];
}
static uint32 BlockNumber8(int x, int y, uint32 bp, uint32 bw)
{
// ASSERT((bw & 1) == 0); // allowed for mipmap levels
return bp + ((y >> 1) & ~0x1f) * (bw >> 1) + ((x >> 2) & ~0x1f) + blockTable8[(y >> 4) & 3][(x >> 4) & 7];
}
static uint32 BlockNumber4(int x, int y, uint32 bp, uint32 bw)
{
// ASSERT((bw & 1) == 0); // allowed for mipmap levels
return bp + ((y >> 2) & ~0x1f) * (bw >> 1) + ((x >> 2) & ~0x1f) + blockTable4[(y >> 4) & 7][(x >> 5) & 3];
}
static uint32 BlockNumber32Z(int x, int y, uint32 bp, uint32 bw)
{
return bp + (y & ~0x1f) * bw + ((x >> 1) & ~0x1f) + blockTable32Z[(y >> 3) & 3][(x >> 3) & 7];
}
static uint32 BlockNumber16Z(int x, int y, uint32 bp, uint32 bw)
{
return bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f) + blockTable16Z[(y >> 3) & 7][(x >> 4) & 3];
}
static uint32 BlockNumber16SZ(int x, int y, uint32 bp, uint32 bw)
{
return bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f) + blockTable16SZ[(y >> 3) & 7][(x >> 4) & 3];
}
uint8* BlockPtr(uint32 bp) const
{
ASSERT(bp < 16384);
return &m_vm8[bp << 8];
}
uint8* BlockPtr32(int x, int y, uint32 bp, uint32 bw) const
{
return &m_vm8[BlockNumber32(x, y, bp, bw) << 8];
}
uint8* BlockPtr16(int x, int y, uint32 bp, uint32 bw) const
{
return &m_vm8[BlockNumber16(x, y, bp, bw) << 8];
}
uint8* BlockPtr16S(int x, int y, uint32 bp, uint32 bw) const
{
return &m_vm8[BlockNumber16S(x, y, bp, bw) << 8];
}
uint8* BlockPtr8(int x, int y, uint32 bp, uint32 bw) const
{
return &m_vm8[BlockNumber8(x, y, bp, bw) << 8];
}
uint8* BlockPtr4(int x, int y, uint32 bp, uint32 bw) const
{
return &m_vm8[BlockNumber4(x, y, bp, bw) << 8];
}
uint8* BlockPtr32Z(int x, int y, uint32 bp, uint32 bw) const
{
return &m_vm8[BlockNumber32Z(x, y, bp, bw) << 8];
}
uint8* BlockPtr16Z(int x, int y, uint32 bp, uint32 bw) const
{
return &m_vm8[BlockNumber16Z(x, y, bp, bw) << 8];
}
uint8* BlockPtr16SZ(int x, int y, uint32 bp, uint32 bw) const
{
return &m_vm8[BlockNumber16SZ(x, y, bp, bw) << 8];
}
static uint32 PixelAddressOrg32(int x, int y, uint32 bp, uint32 bw)
{
return (BlockNumber32(x, y, bp, bw) << 6) + columnTable32[y & 7][x & 7];
}
static uint32 PixelAddressOrg16(int x, int y, uint32 bp, uint32 bw)
{
return (BlockNumber16(x, y, bp, bw) << 7) + columnTable16[y & 7][x & 15];
}
static uint32 PixelAddressOrg16S(int x, int y, uint32 bp, uint32 bw)
{
return (BlockNumber16S(x, y, bp, bw) << 7) + columnTable16[y & 7][x & 15];
}
static uint32 PixelAddressOrg8(int x, int y, uint32 bp, uint32 bw)
{
return (BlockNumber8(x, y, bp, bw) << 8) + columnTable8[y & 15][x & 15];
}
static uint32 PixelAddressOrg4(int x, int y, uint32 bp, uint32 bw)
{
return (BlockNumber4(x, y, bp, bw) << 9) + columnTable4[y & 15][x & 31];
}
static uint32 PixelAddressOrg32Z(int x, int y, uint32 bp, uint32 bw)
{
return (BlockNumber32Z(x, y, bp, bw) << 6) + columnTable32[y & 7][x & 7];
}
static uint32 PixelAddressOrg16Z(int x, int y, uint32 bp, uint32 bw)
{
return (BlockNumber16Z(x, y, bp, bw) << 7) + columnTable16[y & 7][x & 15];
}
static uint32 PixelAddressOrg16SZ(int x, int y, uint32 bp, uint32 bw)
{
return (BlockNumber16SZ(x, y, bp, bw) << 7) + columnTable16[y & 7][x & 15];
}
static __forceinline uint32 PixelAddress32(int x, int y, uint32 bp, uint32 bw)
{
uint32 page = (bp >> 5) + (y >> 5) * bw + (x >> 6);
uint32 word = (page << 11) + pageOffset32[bp & 0x1f][y & 0x1f][x & 0x3f];
return word;
}
static __forceinline uint32 PixelAddress16(int x, int y, uint32 bp, uint32 bw)
{
uint32 page = (bp >> 5) + (y >> 6) * bw + (x >> 6);
uint32 word = (page << 12) + pageOffset16[bp & 0x1f][y & 0x3f][x & 0x3f];
return word;
}
static __forceinline uint32 PixelAddress16S(int x, int y, uint32 bp, uint32 bw)
{
uint32 page = (bp >> 5) + (y >> 6) * bw + (x >> 6);
uint32 word = (page << 12) + pageOffset16S[bp & 0x1f][y & 0x3f][x & 0x3f];
return word;
}
static __forceinline uint32 PixelAddress8(int x, int y, uint32 bp, uint32 bw)
{
// ASSERT((bw & 1) == 0); // allowed for mipmap levels
uint32 page = (bp >> 5) + (y >> 6) * (bw >> 1) + (x >> 7);
uint32 word = (page << 13) + pageOffset8[bp & 0x1f][y & 0x3f][x & 0x7f];
return word;
}
static __forceinline uint32 PixelAddress4(int x, int y, uint32 bp, uint32 bw)
{
// ASSERT((bw & 1) == 0); // allowed for mipmap levels
uint32 page = (bp >> 5) + (y >> 7) * (bw >> 1) + (x >> 7);
uint32 word = (page << 14) + pageOffset4[bp & 0x1f][y & 0x7f][x & 0x7f];
return word;
}
static __forceinline uint32 PixelAddress32Z(int x, int y, uint32 bp, uint32 bw)
{
uint32 page = (bp >> 5) + (y >> 5) * bw + (x >> 6);
uint32 word = (page << 11) + pageOffset32Z[bp & 0x1f][y & 0x1f][x & 0x3f];
return word;
}
static __forceinline uint32 PixelAddress16Z(int x, int y, uint32 bp, uint32 bw)
{
uint32 page = (bp >> 5) + (y >> 6) * bw + (x >> 6);
uint32 word = (page << 12) + pageOffset16Z[bp & 0x1f][y & 0x3f][x & 0x3f];
return word;
}
static __forceinline uint32 PixelAddress16SZ(int x, int y, uint32 bp, uint32 bw)
{
uint32 page = (bp >> 5) + (y >> 6) * bw + (x >> 6);
uint32 word = (page << 12) + pageOffset16SZ[bp & 0x1f][y & 0x3f][x & 0x3f];
return word;
}
// pixel R/W
__forceinline uint32 ReadPixel32(uint32 addr) const
{
return m_vm32[addr];
}
__forceinline uint32 ReadPixel24(uint32 addr) const
{
return m_vm32[addr] & 0x00ffffff;
}
__forceinline uint32 ReadPixel16(uint32 addr) const
{
return (uint32)m_vm16[addr];
}
__forceinline uint32 ReadPixel8(uint32 addr) const
{
return (uint32)m_vm8[addr];
}
__forceinline uint32 ReadPixel4(uint32 addr) const
{
return (m_vm8[addr >> 1] >> ((addr & 1) << 2)) & 0x0f;
}
__forceinline uint32 ReadPixel8H(uint32 addr) const
{
return m_vm32[addr] >> 24;
}
__forceinline uint32 ReadPixel4HL(uint32 addr) const
{
return (m_vm32[addr] >> 24) & 0x0f;
}
__forceinline uint32 ReadPixel4HH(uint32 addr) const
{
return (m_vm32[addr] >> 28) & 0x0f;
}
__forceinline uint32 ReadFrame24(uint32 addr) const
{
return 0x80000000 | (m_vm32[addr] & 0xffffff);
}
__forceinline uint32 ReadFrame16(uint32 addr) const
{
uint32 c = (uint32)m_vm16[addr];
return ((c & 0x8000) << 16) | ((c & 0x7c00) << 9) | ((c & 0x03e0) << 6) | ((c & 0x001f) << 3);
}
__forceinline uint32 ReadPixel32(int x, int y, uint32 bp, uint32 bw) const
{
return ReadPixel32(PixelAddress32(x, y, bp, bw));
}
__forceinline uint32 ReadPixel24(int x, int y, uint32 bp, uint32 bw) const
{
return ReadPixel24(PixelAddress32(x, y, bp, bw));
}
__forceinline uint32 ReadPixel16(int x, int y, uint32 bp, uint32 bw) const
{
return ReadPixel16(PixelAddress16(x, y, bp, bw));
}
__forceinline uint32 ReadPixel16S(int x, int y, uint32 bp, uint32 bw) const
{
return ReadPixel16(PixelAddress16S(x, y, bp, bw));
}
__forceinline uint32 ReadPixel8(int x, int y, uint32 bp, uint32 bw) const
{
return ReadPixel8(PixelAddress8(x, y, bp, bw));
}
__forceinline uint32 ReadPixel4(int x, int y, uint32 bp, uint32 bw) const
{
return ReadPixel4(PixelAddress4(x, y, bp, bw));
}
__forceinline uint32 ReadPixel8H(int x, int y, uint32 bp, uint32 bw) const
{
return ReadPixel8H(PixelAddress32(x, y, bp, bw));
}
__forceinline uint32 ReadPixel4HL(int x, int y, uint32 bp, uint32 bw) const
{
return ReadPixel4HL(PixelAddress32(x, y, bp, bw));
}
__forceinline uint32 ReadPixel4HH(int x, int y, uint32 bp, uint32 bw) const
{
return ReadPixel4HH(PixelAddress32(x, y, bp, bw));
}
__forceinline uint32 ReadPixel32Z(int x, int y, uint32 bp, uint32 bw) const
{
return ReadPixel32(PixelAddress32Z(x, y, bp, bw));
}
__forceinline uint32 ReadPixel24Z(int x, int y, uint32 bp, uint32 bw) const
{
return ReadPixel24(PixelAddress32Z(x, y, bp, bw));
}
__forceinline uint32 ReadPixel16Z(int x, int y, uint32 bp, uint32 bw) const
{
return ReadPixel16(PixelAddress16Z(x, y, bp, bw));
}
__forceinline uint32 ReadPixel16SZ(int x, int y, uint32 bp, uint32 bw) const
{
return ReadPixel16(PixelAddress16SZ(x, y, bp, bw));
}
__forceinline uint32 ReadFrame24(int x, int y, uint32 bp, uint32 bw) const
{
return ReadFrame24(PixelAddress32(x, y, bp, bw));
}
__forceinline uint32 ReadFrame16(int x, int y, uint32 bp, uint32 bw) const
{
return ReadFrame16(PixelAddress16(x, y, bp, bw));
}
__forceinline uint32 ReadFrame16S(int x, int y, uint32 bp, uint32 bw) const
{
return ReadFrame16(PixelAddress16S(x, y, bp, bw));
}
__forceinline uint32 ReadFrame24Z(int x, int y, uint32 bp, uint32 bw) const
{
return ReadFrame24(PixelAddress32Z(x, y, bp, bw));
}
__forceinline uint32 ReadFrame16Z(int x, int y, uint32 bp, uint32 bw) const
{
return ReadFrame16(PixelAddress16Z(x, y, bp, bw));
}
__forceinline uint32 ReadFrame16SZ(int x, int y, uint32 bp, uint32 bw) const
{
return ReadFrame16(PixelAddress16SZ(x, y, bp, bw));
}
__forceinline void WritePixel32(uint32 addr, uint32 c)
{
m_vm32[addr] = c;
}
__forceinline void WritePixel24(uint32 addr, uint32 c)
{
m_vm32[addr] = (m_vm32[addr] & 0xff000000) | (c & 0x00ffffff);
}
__forceinline void WritePixel16(uint32 addr, uint32 c)
{
m_vm16[addr] = (uint16)c;
}
__forceinline void WritePixel8(uint32 addr, uint32 c)
{
m_vm8[addr] = (uint8)c;
}
__forceinline void WritePixel4(uint32 addr, uint32 c)
{
int shift = (addr & 1) << 2; addr >>= 1;
m_vm8[addr] = (uint8)((m_vm8[addr] & (0xf0 >> shift)) | ((c & 0x0f) << shift));
}
__forceinline void WritePixel8H(uint32 addr, uint32 c)
{
m_vm32[addr] = (m_vm32[addr] & 0x00ffffff) | (c << 24);
}
__forceinline void WritePixel4HL(uint32 addr, uint32 c)
{
m_vm32[addr] = (m_vm32[addr] & 0xf0ffffff) | ((c & 0x0f) << 24);
}
__forceinline void WritePixel4HH(uint32 addr, uint32 c)
{
m_vm32[addr] = (m_vm32[addr] & 0x0fffffff) | ((c & 0x0f) << 28);
}
__forceinline void WriteFrame16(uint32 addr, uint32 c)
{
uint32 rb = c & 0x00f800f8;
uint32 ga = c & 0x8000f800;
WritePixel16(addr, (ga >> 16) | (rb >> 9) | (ga >> 6) | (rb >> 3));
}
__forceinline void WritePixel32(int x, int y, uint32 c, uint32 bp, uint32 bw)
{
WritePixel32(PixelAddress32(x, y, bp, bw), c);
}
__forceinline void WritePixel24(int x, int y, uint32 c, uint32 bp, uint32 bw)
{
WritePixel24(PixelAddress32(x, y, bp, bw), c);
}
__forceinline void WritePixel16(int x, int y, uint32 c, uint32 bp, uint32 bw)
{
WritePixel16(PixelAddress16(x, y, bp, bw), c);
}
__forceinline void WritePixel16S(int x, int y, uint32 c, uint32 bp, uint32 bw)
{
WritePixel16(PixelAddress16S(x, y, bp, bw), c);
}
__forceinline void WritePixel8(int x, int y, uint32 c, uint32 bp, uint32 bw)
{
WritePixel8(PixelAddress8(x, y, bp, bw), c);
}
__forceinline void WritePixel4(int x, int y, uint32 c, uint32 bp, uint32 bw)
{
WritePixel4(PixelAddress4(x, y, bp, bw), c);
}
__forceinline void WritePixel8H(int x, int y, uint32 c, uint32 bp, uint32 bw)
{
WritePixel8H(PixelAddress32(x, y, bp, bw), c);
}
__forceinline void WritePixel4HL(int x, int y, uint32 c, uint32 bp, uint32 bw)
{
WritePixel4HL(PixelAddress32(x, y, bp, bw), c);
}
__forceinline void WritePixel4HH(int x, int y, uint32 c, uint32 bp, uint32 bw)
{
WritePixel4HH(PixelAddress32(x, y, bp, bw), c);
}
__forceinline void WritePixel32Z(int x, int y, uint32 c, uint32 bp, uint32 bw)
{
WritePixel32(PixelAddress32Z(x, y, bp, bw), c);
}
__forceinline void WritePixel24Z(int x, int y, uint32 c, uint32 bp, uint32 bw)
{
WritePixel24(PixelAddress32Z(x, y, bp, bw), c);
}
__forceinline void WritePixel16Z(int x, int y, uint32 c, uint32 bp, uint32 bw)
{
WritePixel16(PixelAddress16Z(x, y, bp, bw), c);
}
__forceinline void WritePixel16SZ(int x, int y, uint32 c, uint32 bp, uint32 bw)
{
WritePixel16(PixelAddress16SZ(x, y, bp, bw), c);
}
__forceinline void WriteFrame16(int x, int y, uint32 c, uint32 bp, uint32 bw)
{
WriteFrame16(PixelAddress16(x, y, bp, bw), c);
}
__forceinline void WriteFrame16S(int x, int y, uint32 c, uint32 bp, uint32 bw)
{
WriteFrame16(PixelAddress16S(x, y, bp, bw), c);
}
__forceinline void WriteFrame16Z(int x, int y, uint32 c, uint32 bp, uint32 bw)
{
WriteFrame16(PixelAddress16Z(x, y, bp, bw), c);
}
__forceinline void WriteFrame16SZ(int x, int y, uint32 c, uint32 bp, uint32 bw)
{
WriteFrame16(PixelAddress16SZ(x, y, bp, bw), c);
}
__forceinline void WritePixel32(uint8* RESTRICT src, uint32 pitch, GSOffset* off, const GSVector4i& r)
{
src -= r.left * sizeof(uint32);
for(int y = r.top; y < r.bottom; y++, src += pitch)
{
uint32* RESTRICT s = (uint32*)src;
uint32* RESTRICT d = &m_vm32[off->pixel.row[y]];
int* RESTRICT col = off->pixel.col[0];
for(int x = r.left; x < r.right; x++)
{
d[col[x]] = s[x];
}
}
}
__forceinline void WritePixel24(uint8* RESTRICT src, uint32 pitch, GSOffset* off, const GSVector4i& r)
{
src -= r.left * sizeof(uint32);
for(int y = r.top; y < r.bottom; y++, src += pitch)
{
uint32* RESTRICT s = (uint32*)src;
uint32* RESTRICT d = &m_vm32[off->pixel.row[y]];
int* RESTRICT col = off->pixel.col[0];
for(int x = r.left; x < r.right; x++)
{
d[col[x]] = (d[col[x]] & 0xff000000) | (s[x] & 0x00ffffff);
}
}
}
__forceinline void WritePixel16(uint8* RESTRICT src, uint32 pitch, GSOffset* off, const GSVector4i& r)
{
src -= r.left * sizeof(uint16);
for(int y = r.top; y < r.bottom; y++, src += pitch)
{
uint16* RESTRICT s = (uint16*)src;
uint16* RESTRICT d = &m_vm16[off->pixel.row[y]];
int* RESTRICT col = off->pixel.col[0];
for(int x = r.left; x < r.right; x++)
{
d[col[x]] = s[x];
}
}
}
__forceinline void WriteFrame16(uint8* RESTRICT src, uint32 pitch, GSOffset* off, const GSVector4i& r)
{
src -= r.left * sizeof(uint32);
for(int y = r.top; y < r.bottom; y++, src += pitch)
{
uint32* RESTRICT s = (uint32*)src;
uint16* RESTRICT d = &m_vm16[off->pixel.row[y]];
int* RESTRICT col = off->pixel.col[0];
for(int x = r.left; x < r.right; x++)
{
uint32 rb = s[x] & 0x00f800f8;
uint32 ga = s[x] & 0x8000f800;
d[col[x]] = (uint16)((ga >> 16) | (rb >> 9) | (ga >> 6) | (rb >> 3));
}
}
}
__forceinline uint32 ReadTexel32(uint32 addr, const GIFRegTEXA& TEXA) const
{
return m_vm32[addr];
}
__forceinline uint32 ReadTexel24(uint32 addr, const GIFRegTEXA& TEXA) const
{
return Expand24To32(m_vm32[addr], TEXA);
}
__forceinline uint32 ReadTexel16(uint32 addr, const GIFRegTEXA& TEXA) const
{
return Expand16To32(m_vm16[addr], TEXA);
}
__forceinline uint32 ReadTexel8(uint32 addr, const GIFRegTEXA& TEXA) const
{
return m_clut[ReadPixel8(addr)];
}
__forceinline uint32 ReadTexel4(uint32 addr, const GIFRegTEXA& TEXA) const
{
return m_clut[ReadPixel4(addr)];
}
__forceinline uint32 ReadTexel8H(uint32 addr, const GIFRegTEXA& TEXA) const
{
return m_clut[ReadPixel8H(addr)];
}
__forceinline uint32 ReadTexel4HL(uint32 addr, const GIFRegTEXA& TEXA) const
{
return m_clut[ReadPixel4HL(addr)];
}
__forceinline uint32 ReadTexel4HH(uint32 addr, const GIFRegTEXA& TEXA) const
{
return m_clut[ReadPixel4HH(addr)];
}
__forceinline uint32 ReadTexel32(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const
{
return ReadTexel32(PixelAddress32(x, y, TEX0.TBP0, TEX0.TBW), TEXA);
}
__forceinline uint32 ReadTexel24(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const
{
return ReadTexel24(PixelAddress32(x, y, TEX0.TBP0, TEX0.TBW), TEXA);
}
__forceinline uint32 ReadTexel16(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const
{
return ReadTexel16(PixelAddress16(x, y, TEX0.TBP0, TEX0.TBW), TEXA);
}
__forceinline uint32 ReadTexel16S(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const
{
return ReadTexel16(PixelAddress16S(x, y, TEX0.TBP0, TEX0.TBW), TEXA);
}
__forceinline uint32 ReadTexel8(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const
{
return ReadTexel8(PixelAddress8(x, y, TEX0.TBP0, TEX0.TBW), TEXA);
}
__forceinline uint32 ReadTexel4(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const
{
return ReadTexel4(PixelAddress4(x, y, TEX0.TBP0, TEX0.TBW), TEXA);
}
__forceinline uint32 ReadTexel8H(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const
{
return ReadTexel8H(PixelAddress32(x, y, TEX0.TBP0, TEX0.TBW), TEXA);
}
__forceinline uint32 ReadTexel4HL(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const
{
return ReadTexel4HL(PixelAddress32(x, y, TEX0.TBP0, TEX0.TBW), TEXA);
}
__forceinline uint32 ReadTexel4HH(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const
{
return ReadTexel4HH(PixelAddress32(x, y, TEX0.TBP0, TEX0.TBW), TEXA);
}
__forceinline uint32 ReadTexel32Z(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const
{
return ReadTexel32(PixelAddress32Z(x, y, TEX0.TBP0, TEX0.TBW), TEXA);
}
__forceinline uint32 ReadTexel24Z(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const
{
return ReadTexel24(PixelAddress32Z(x, y, TEX0.TBP0, TEX0.TBW), TEXA);
}
__forceinline uint32 ReadTexel16Z(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const
{
return ReadTexel16(PixelAddress16Z(x, y, TEX0.TBP0, TEX0.TBW), TEXA);
}
__forceinline uint32 ReadTexel16SZ(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const
{
return ReadTexel16(PixelAddress16SZ(x, y, TEX0.TBP0, TEX0.TBW), TEXA);
}
//
template<int psm, int bsx, int bsy, int alignment>
void WriteImageColumn(int l, int r, int y, int h, const uint8* src, int srcpitch, const GIFRegBITBLTBUF& BITBLTBUF);
template<int psm, int bsx, int bsy, int alignment>
void WriteImageBlock(int l, int r, int y, int h, const uint8* src, int srcpitch, const GIFRegBITBLTBUF& BITBLTBUF);
template<int psm, int bsx, int bsy>
void WriteImageLeftRight(int l, int r, int y, int h, const uint8* src, int srcpitch, const GIFRegBITBLTBUF& BITBLTBUF);
template<int psm, int bsx, int bsy, int trbpp>
void WriteImageTopBottom(int l, int r, int y, int h, const uint8* src, int srcpitch, const GIFRegBITBLTBUF& BITBLTBUF);
template<int psm, int bsx, int bsy, int trbpp>
void WriteImage(int& tx, int& ty, const uint8* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG);
void WriteImage24(int& tx, int& ty, const uint8* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG);
void WriteImage8H(int& tx, int& ty, const uint8* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG);
void WriteImage4HL(int& tx, int& ty, const uint8* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG);
void WriteImage4HH(int& tx, int& ty, const uint8* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG);
void WriteImage24Z(int& tx, int& ty, const uint8* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG);
void WriteImageX(int& tx, int& ty, const uint8* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG);
// TODO: ReadImage32/24/...
void ReadImageX(int& tx, int& ty, uint8* dst, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) const;
// * => 32
void ReadTexture32(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
void ReadTexture24(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
void ReadTexture16(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
void ReadTexture8(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
void ReadTexture4(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
void ReadTexture8H(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
void ReadTexture4HL(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
void ReadTexture4HH(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
void ReadTexture(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
void ReadTextureBlock32(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const;
void ReadTextureBlock24(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const;
void ReadTextureBlock16(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const;
void ReadTextureBlock8(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const;
void ReadTextureBlock4(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const;
void ReadTextureBlock8H(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const;
void ReadTextureBlock4HL(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const;
void ReadTextureBlock4HH(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const;
// pal ? 8 : 32
void ReadTexture8P(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
void ReadTexture4P(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
void ReadTexture8HP(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
void ReadTexture4HLP(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
void ReadTexture4HHP(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
void ReadTextureBlock8P(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const;
void ReadTextureBlock4P(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const;
void ReadTextureBlock8HP(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const;
void ReadTextureBlock4HLP(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const;
void ReadTextureBlock4HHP(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const;
//
template<typename T> void ReadTexture(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
//
void SaveBMP(const string& fn, uint32 bp, uint32 bw, uint32 psm, int w, int h);
};

View File

@ -0,0 +1,161 @@
/*
* Copyright (C) 2015-2015 Gregory hainaut
*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSLzma.h"
#ifdef __linux__
GSDumpFile::GSDumpFile(char* filename) {
m_fp = fopen(filename, "rb");
if (m_fp == NULL) {
fprintf(stderr, "failed to open %s\n", filename);
throw "BAD"; // Just exit the program
}
}
GSDumpFile::~GSDumpFile() {
if (m_fp)
fclose(m_fp);
}
/******************************************************************/
#ifdef LZMA_SUPPORTED
GSDumpLzma::GSDumpLzma(char* filename) : GSDumpFile(filename) {
memset(&m_strm, 0, sizeof(lzma_stream));
lzma_ret ret = lzma_stream_decoder(&m_strm, UINT32_MAX, 0);
if (ret != LZMA_OK) {
fprintf(stderr, "Error initializing the decoder! (error code %u)\n", ret);
throw "BAD"; // Just exit the program
}
m_buff_size = 1024*1024;
m_area = (uint8_t*)_aligned_malloc(m_buff_size, 32);
m_inbuf = (uint8_t*)_aligned_malloc(BUFSIZ, 32);
m_avail = 0;
m_start = 0;
m_strm.avail_in = 0;
m_strm.next_in = m_inbuf;
m_strm.avail_out = m_buff_size;
m_strm.next_out = m_area;
}
void GSDumpLzma::Decompress() {
lzma_action action = LZMA_RUN;
m_strm.next_out = m_area;
m_strm.avail_out = m_buff_size;
// Nothing left in the input buffer. Read data from the file
if (m_strm.avail_in == 0 && !feof(m_fp)) {
m_strm.next_in = m_inbuf;
m_strm.avail_in = fread(m_inbuf, 1, BUFSIZ, m_fp);
if (ferror(m_fp)) {
fprintf(stderr, "Read error: %s\n", strerror(errno));
throw "BAD"; // Just exit the program
}
}
lzma_ret ret = lzma_code(&m_strm, action);
if (ret != LZMA_OK) {
if (ret == LZMA_STREAM_END)
fprintf(stderr, "LZMA decoder finished without error\n\n");
else {
fprintf(stderr, "Decoder error: (error code %u)\n", ret);
throw "BAD"; // Just exit the program
}
}
m_start = 0;
m_avail = m_buff_size - m_strm.avail_out;
}
bool GSDumpLzma::IsEof() {
return feof(m_fp) && (m_avail == 0);
}
void GSDumpLzma::Read(void* ptr, size_t size) {
size_t off = 0;
uint8_t* dst = (uint8_t*)ptr;
while (size) {
if (m_avail == 0) {
Decompress();
}
size_t l = min(size, m_avail);
memcpy(dst + off, m_area+m_start, l);
m_avail -= l;
size -= l;
m_start += l;
off += l;
}
}
GSDumpLzma::~GSDumpLzma() {
lzma_end(&m_strm);
if (m_inbuf)
_aligned_free(m_inbuf);
if (m_area)
_aligned_free(m_area);
}
#endif
/******************************************************************/
GSDumpRaw::GSDumpRaw(char* filename) : GSDumpFile(filename) {
m_buff_size = 0;
m_area = NULL;
m_inbuf = NULL;
m_avail = 0;
m_start = 0;
}
GSDumpRaw::~GSDumpRaw() {
}
bool GSDumpRaw::IsEof() {
return feof(m_fp);
}
void GSDumpRaw::Read(void* ptr, size_t size) {
if (size == 1) {
// I don't know why but read of size 1 is not happy
int v = fgetc(m_fp);
memcpy(ptr, &v, 1);
} else {
size_t ret = fread(ptr, 1, size, m_fp);
if (ret != size) {
fprintf(stderr, "GSDumpRaw:: Read error\n");
throw "BAD"; // Just exit the program
}
}
}
#endif

View File

@ -0,0 +1,84 @@
/*
* Copyright (C) 2015-2015 Gregory hainaut
*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#ifdef __linux__
#ifdef LZMA_SUPPORTED
#include <lzma.h>
#endif
class GSDumpFile {
protected:
FILE* m_fp;
public:
virtual bool IsEof() = 0;
virtual void Read(void* ptr, size_t size) = 0;
GSDumpFile(char* filename);
virtual ~GSDumpFile();
};
#ifdef LZMA_SUPPORTED
class GSDumpLzma : public GSDumpFile {
lzma_stream m_strm;
size_t m_buff_size;
uint8_t* m_area;
uint8_t* m_inbuf;
size_t m_avail;
size_t m_start;
void Decompress();
public:
GSDumpLzma(char* filename);
virtual ~GSDumpLzma();
bool IsEof();
void Read(void* ptr, size_t size);
};
#endif
class GSDumpRaw : public GSDumpFile {
size_t m_buff_size;
uint8_t* m_area;
uint8_t* m_inbuf;
size_t m_avail;
size_t m_start;
void Decompress();
public:
GSDumpRaw(char* filename);
virtual ~GSDumpRaw();
bool IsEof();
void Read(void* ptr, size_t size);
};
#endif

View File

@ -0,0 +1,119 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSPerfMon.h"
GSPerfMon::GSPerfMon()
: m_frame(0)
, m_lastframe(0)
, m_count(0)
{
memset(m_counters, 0, sizeof(m_counters));
memset(m_stats, 0, sizeof(m_stats));
memset(m_total, 0, sizeof(m_total));
memset(m_begin, 0, sizeof(m_begin));
}
void GSPerfMon::Put(counter_t c, double val)
{
#ifndef DISABLE_PERF_MON
if(c == Frame)
{
#ifdef __linux__
// clock on linux will return CLOCK_PROCESS_CPUTIME_ID.
// CLOCK_THREAD_CPUTIME_ID is much more useful to measure the fps
struct timespec ts;
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
uint64 now = (uint64) ts.tv_sec * (uint64) 1e6 + (uint64) ts.tv_nsec / (uint64) 1e3;
#else
clock_t now = clock();
#endif
if(m_lastframe != 0)
{
m_counters[c] += (now - m_lastframe) * 1000 / CLOCKS_PER_SEC;
}
m_lastframe = now;
m_frame++;
m_count++;
}
else
{
m_counters[c] += val;
}
#endif
}
void GSPerfMon::Update()
{
#ifndef DISABLE_PERF_MON
if(m_count > 0)
{
for(size_t i = 0; i < countof(m_counters); i++)
{
m_stats[i] = m_counters[i] / m_count;
}
m_count = 0;
}
memset(m_counters, 0, sizeof(m_counters));
#endif
}
void GSPerfMon::Start(int timer)
{
#ifndef DISABLE_PERF_MON
m_start[timer] = __rdtsc();
if(m_begin[timer] == 0)
{
m_begin[timer] = m_start[timer];
}
#endif
}
void GSPerfMon::Stop(int timer)
{
#ifndef DISABLE_PERF_MON
if(m_start[timer] > 0)
{
m_total[timer] += __rdtsc() - m_start[timer];
m_start[timer] = 0;
}
#endif
}
int GSPerfMon::CPU(int timer, bool reset)
{
int percent = (int)(100 * m_total[timer] / (__rdtsc() - m_begin[timer]));
if(reset)
{
m_begin[timer] = 0;
m_start[timer] = 0;
m_total[timer] = 0;
}
return percent;
}

View File

@ -0,0 +1,75 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
class GSPerfMon
{
public:
enum timer_t
{
Main,
Sync,
WorkerDraw0, WorkerDraw1, WorkerDraw2, WorkerDraw3, WorkerDraw4, WorkerDraw5, WorkerDraw6, WorkerDraw7,
WorkerDraw8, WorkerDraw9, WorkerDraw10, WorkerDraw11, WorkerDraw12, WorkerDraw13, WorkerDraw14, WorkerDraw15,
TimerLast,
};
enum counter_t
{
Frame, Prim, Draw, Swizzle, Unswizzle, Fillrate, Quad, SyncPoint,
CounterLast,
};
protected:
double m_counters[CounterLast];
double m_stats[CounterLast];
uint64 m_begin[TimerLast], m_total[TimerLast], m_start[TimerLast];
uint64 m_frame;
clock_t m_lastframe;
int m_count;
friend class GSPerfMonAutoTimer;
public:
GSPerfMon();
void SetFrame(uint64 frame) {m_frame = frame;}
uint64 GetFrame() {return m_frame;}
void Put(counter_t c, double val = 0);
double Get(counter_t c) {return m_stats[c];}
void Update();
void Start(int timer = Main);
void Stop(int timer = Main);
int CPU(int timer = Main, bool reset = true);
};
class GSPerfMonAutoTimer
{
GSPerfMon* m_pm;
int m_timer;
public:
GSPerfMonAutoTimer(GSPerfMon* pm, int timer = GSPerfMon::Main) {m_timer = timer; (m_pm = pm)->Start(m_timer);}
~GSPerfMonAutoTimer() {m_pm->Stop(m_timer);}
};

View File

@ -0,0 +1,149 @@
/*
* Copyright (C) 2015-2015 Gregory hainaut
*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSPng.h"
#include <zlib.h>
#include <png.h>
struct {
int type;
int bytes_per_pixel_in;
int bytes_per_pixel_out;
int channel_bit_depth;
const char *extension[2];
} static const pixel[GSPng::Format::COUNT] = {
{PNG_COLOR_TYPE_RGBA, 4, 4, 8 , {"_full.png", nullptr}}, // RGBA_PNG
{PNG_COLOR_TYPE_RGB , 4, 3, 8 , {".png", nullptr}}, // RGB_PNG
{PNG_COLOR_TYPE_RGB , 4, 3, 8 , {".png", "_alpha.png"}}, // RGB_A_PNG
{PNG_COLOR_TYPE_GRAY, 4, 1, 8 , {"_alpha.png", nullptr}}, // ALPHA_PNG
{PNG_COLOR_TYPE_GRAY, 1, 1, 8 , {"_R8I.png", nullptr}}, // R8I_PNG
{PNG_COLOR_TYPE_GRAY, 2, 2, 16, {"_R16I.png", nullptr}}, // R16I_PNG
{PNG_COLOR_TYPE_GRAY, 4, 2, 16, {"_R32I_lsb.png", "_R32I_msb.png"}}, // R32I_PNG
};
namespace GSPng {
bool SaveFile(const string& file, Format fmt, uint8* image, uint8* row,
int width, int height, int pitch, int compression,
bool rb_swapped = false, bool first_image = false)
{
int channel_bit_depth = pixel[fmt].channel_bit_depth;
int bytes_per_pixel_in = pixel[fmt].bytes_per_pixel_in;
int type = first_image ? pixel[fmt].type : PNG_COLOR_TYPE_GRAY;
int offset = first_image ? 0 : pixel[fmt].bytes_per_pixel_out;
int bytes_per_pixel_out = first_image ? pixel[fmt].bytes_per_pixel_out : bytes_per_pixel_in - offset;
FILE *fp = fopen(file.c_str(), "wb");
if (fp == nullptr)
return false;
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
png_infop info_ptr = nullptr;
bool success = false;
try {
if (png_ptr == nullptr)
throw GSDXRecoverableError();
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == nullptr)
throw GSDXRecoverableError();
if (setjmp(png_jmpbuf(png_ptr)))
throw GSDXRecoverableError();
if (compression < 0 || compression > Z_BEST_COMPRESSION)
compression = Z_BEST_SPEED;
png_init_io(png_ptr, fp);
png_set_compression_level(png_ptr, compression);
png_set_IHDR(png_ptr, info_ptr, width, height, channel_bit_depth, type,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_write_info(png_ptr, info_ptr);
if (channel_bit_depth > 8)
png_set_swap(png_ptr);
if (rb_swapped && type != PNG_COLOR_TYPE_GRAY)
png_set_bgr(png_ptr);
for (int y = 0; y < height; ++y, image += pitch) {
for (int x = 0; x < width; ++x)
for (int i = 0; i < bytes_per_pixel_out; ++i)
row[bytes_per_pixel_out * x + i] = image[bytes_per_pixel_in * x + i + offset];
png_write_row(png_ptr, row);
}
png_write_end(png_ptr, nullptr);
success = true;
} catch (GSDXRecoverableError&) {
fprintf(stderr, "Failed to write image %s\n", file.c_str());
}
if (png_ptr)
png_destroy_write_struct(&png_ptr, info_ptr ? &info_ptr : nullptr);
fclose(fp);
return success;
}
bool Save(GSPng::Format fmt, const string& file, uint8* image, int w, int h, int pitch, int compression, bool rb_swapped)
{
std::string root = file;
root.replace(file.length() - 4, 4, "");
ASSERT(fmt >= Format::START && fmt < Format::COUNT);
std::unique_ptr<uint8[]> row(new uint8[pixel[fmt].bytes_per_pixel_out * w]);
std::string filename = root + pixel[fmt].extension[0];
if (!SaveFile(filename, fmt, image, row.get(), w, h, pitch, compression, rb_swapped, true))
return false;
// Second image
if (pixel[fmt].extension[1] == nullptr)
return true;
filename = root + pixel[fmt].extension[1];
return SaveFile(filename, fmt, image, row.get(), w, h, pitch, compression);
}
Transaction::Transaction(GSPng::Format fmt, const string& file, const uint8* image, int w, int h, int pitch, int compression)
: m_fmt(fmt), m_file(file), m_w(w), m_h(h), m_pitch(pitch), m_compression(compression)
{
// Note: yes it would be better to use shared pointer
m_image = (uint8*)_aligned_malloc(pitch*h, 32);
if (m_image)
memcpy(m_image, image, pitch*h);
}
Transaction::~Transaction()
{
if (m_image)
_aligned_free(m_image);
}
void Worker::Process(shared_ptr<Transaction>& item)
{
Save(item->m_fmt, item->m_file, item->m_image, item->m_w, item->m_h, item->m_pitch, item->m_compression);
}
}

View File

@ -0,0 +1,65 @@
/*
* Copyright (C) 2015-2015 Gregory hainaut
*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSThread_CXX11.h"
namespace GSPng {
enum Format {
START = 0,
RGBA_PNG = 0,
RGB_PNG,
RGB_A_PNG,
ALPHA_PNG,
R8I_PNG,
R16I_PNG,
R32I_PNG,
COUNT
};
class Transaction
{
public:
Format m_fmt;
const std::string m_file;
uint8* m_image;
int m_w;
int m_h;
int m_pitch;
int m_compression;
Transaction(GSPng::Format fmt, const string& file, const uint8* image, int w, int h, int pitch, int compression);
~Transaction();
};
bool Save(GSPng::Format fmt, const string& file, uint8* image, int w, int h, int pitch, int compression, bool rb_swapped = false);
class Worker : public GSJobQueue<shared_ptr<Transaction>, 16 >
{
public:
Worker() {};
virtual ~Worker() {};
void Process(shared_ptr<Transaction>& item);
int GetPixels(bool reset) {return 0;}
};
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,235 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GS.h"
#include "GSVertexSW.h"
#include "GSFunctionMap.h"
#include "GSAlignedClass.h"
#include "GSPerfMon.h"
#include "GSThread_CXX11.h"
__aligned(class, 32) GSRasterizerData : public GSAlignedClass<32>
{
static int s_counter;
public:
GSVector4i scissor;
GSVector4i bbox;
GS_PRIM_CLASS primclass;
uint8* buff;
GSVertexSW* vertex;
int vertex_count;
uint32* index;
int index_count;
uint64 frame;
uint64 start;
int pixels;
int counter;
GSRasterizerData()
: scissor(GSVector4i::zero())
, bbox(GSVector4i::zero())
, primclass(GS_INVALID_CLASS)
, buff(NULL)
, vertex(NULL)
, vertex_count(0)
, index(NULL)
, index_count(0)
, frame(0)
, start(0)
, pixels(0)
{
counter = s_counter++;
}
virtual ~GSRasterizerData()
{
if(buff != NULL) _aligned_free(buff);
}
};
class IDrawScanline : public GSAlignedClass<32>
{
public:
typedef void (*SetupPrimPtr)(const GSVertexSW* vertex, const uint32* index, const GSVertexSW& dscan);
typedef void (__fastcall *DrawScanlinePtr)(int pixels, int left, int top, const GSVertexSW& scan);
typedef void (IDrawScanline::*DrawRectPtr)(const GSVector4i& r, const GSVertexSW& v); // TODO: jit
protected:
SetupPrimPtr m_sp;
DrawScanlinePtr m_ds;
DrawScanlinePtr m_de;
DrawRectPtr m_dr;
public:
IDrawScanline() : m_sp(NULL), m_ds(NULL), m_de(NULL), m_dr(NULL) {}
virtual ~IDrawScanline() {}
virtual void BeginDraw(const GSRasterizerData* data) = 0;
virtual void EndDraw(uint64 frame, uint64 ticks, int actual, int total) = 0;
#ifdef ENABLE_JIT_RASTERIZER
__forceinline void SetupPrim(const GSVertexSW* vertex, const uint32* index, const GSVertexSW& dscan) {m_sp(vertex, index, dscan);}
__forceinline void DrawScanline(int pixels, int left, int top, const GSVertexSW& scan) {m_ds(pixels, left, top, scan);}
__forceinline void DrawEdge(int pixels, int left, int top, const GSVertexSW& scan) {m_de(pixels, left, top, scan);}
__forceinline void DrawRect(const GSVector4i& r, const GSVertexSW& v) {(this->*m_dr)(r, v);}
#else
virtual void SetupPrim(const GSVertexSW* vertex, const uint32* index, const GSVertexSW& dscan) = 0;
virtual void DrawScanline(int pixels, int left, int top, const GSVertexSW& scan) = 0;
virtual void DrawEdge(int pixels, int left, int top, const GSVertexSW& scan) = 0;
virtual void DrawRect(const GSVector4i& r, const GSVertexSW& v) = 0;
#endif
virtual void PrintStats() = 0;
__forceinline bool HasEdge() const {return m_de != NULL;}
__forceinline bool IsSolidRect() const {return m_dr != NULL;}
};
class IRasterizer : public GSAlignedClass<32>
{
public:
virtual ~IRasterizer() {}
virtual void Queue(const shared_ptr<GSRasterizerData>& data) = 0;
virtual void Sync() = 0;
virtual bool IsSynced() const = 0;
virtual int GetPixels(bool reset = true) = 0;
virtual void PrintStats() = 0;
};
__aligned(class, 32) GSRasterizer : public IRasterizer
{
protected:
GSPerfMon* m_perfmon;
IDrawScanline* m_ds;
int m_id;
int m_threads;
uint8* m_scanline;
GSVector4i m_scissor;
GSVector4 m_fscissor_x;
GSVector4 m_fscissor_y;
struct {GSVertexSW* buff; int count;} m_edge;
struct {int sum, actual, total;} m_pixels;
typedef void (GSRasterizer::*DrawPrimPtr)(const GSVertexSW* v, int count);
template<bool scissor_test>
void DrawPoint(const GSVertexSW* vertex, int vertex_count, const uint32* index, int index_count);
void DrawLine(const GSVertexSW* vertex, const uint32* index);
void DrawTriangle(const GSVertexSW* vertex, const uint32* index);
void DrawSprite(const GSVertexSW* vertex, const uint32* index);
#if _M_SSE >= 0x501
__forceinline void DrawTriangleSection(int top, int bottom, GSVertexSW2& edge, const GSVertexSW2& dedge, const GSVertexSW2& dscan, const GSVector4& p0);
#else
__forceinline void DrawTriangleSection(int top, int bottom, GSVertexSW& edge, const GSVertexSW& dedge, const GSVertexSW& dscan, const GSVector4& p0);
#endif
void DrawEdge(const GSVertexSW& v0, const GSVertexSW& v1, const GSVertexSW& dv, int orientation, int side);
__forceinline void AddScanline(GSVertexSW* e, int pixels, int left, int top, const GSVertexSW& scan);
__forceinline void Flush(const GSVertexSW* vertex, const uint32* index, const GSVertexSW& dscan, bool edge = false);
__forceinline void DrawScanline(int pixels, int left, int top, const GSVertexSW& scan);
__forceinline void DrawEdge(int pixels, int left, int top, const GSVertexSW& scan);
public:
GSRasterizer(IDrawScanline* ds, int id, int threads, GSPerfMon* perfmon);
virtual ~GSRasterizer();
__forceinline bool IsOneOfMyScanlines(int top) const;
__forceinline bool IsOneOfMyScanlines(int top, int bottom) const;
__forceinline int FindMyNextScanline(int top) const;
void Draw(GSRasterizerData* data);
// IRasterizer
void Queue(const shared_ptr<GSRasterizerData>& data);
void Sync() {}
bool IsSynced() const {return true;}
int GetPixels(bool reset);
void PrintStats() {m_ds->PrintStats();}
};
class GSRasterizerList : public IRasterizer
{
protected:
class GSWorker : public GSJobQueue<shared_ptr<GSRasterizerData>, 256 >
{
GSRasterizer* m_r;
public:
GSWorker(GSRasterizer* r);
virtual ~GSWorker();
int GetPixels(bool reset);
// GSJobQueue
void Process(shared_ptr<GSRasterizerData>& item);
};
GSPerfMon* m_perfmon;
vector<GSWorker*> m_workers;
uint8* m_scanline;
GSRasterizerList(int threads, GSPerfMon* perfmon);
public:
virtual ~GSRasterizerList();
template<class DS> static IRasterizer* Create(int threads, GSPerfMon* perfmon)
{
threads = std::max<int>(threads, 0);
if(threads == 0)
{
return new GSRasterizer(new DS(), 0, 1, perfmon);
}
else
{
GSRasterizerList* rl = new GSRasterizerList(threads, perfmon);
for(int i = 0; i < threads; i++)
{
rl->m_workers.push_back(new GSWorker(new GSRasterizer(new DS(), i, threads, perfmon)));
}
return rl;
}
}
// IRasterizer
void Queue(const shared_ptr<GSRasterizerData>& data);
void Sync();
bool IsSynced() const;
int GetPixels(bool reset);
void PrintStats() {}
};

View File

@ -0,0 +1,654 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSRenderer.h"
#ifdef __linux__
#include <X11/keysym.h>
#endif
const unsigned int s_interlace_nb = 8;
const unsigned int s_post_shader_nb = 5;
const unsigned int s_aspect_ratio_nb = 3;
GSRenderer::GSRenderer()
: m_shader(0)
, m_shift_key(false)
, m_control_key(false)
, m_framelimit(false)
, m_texture_shuffle(false)
, m_wnd(NULL)
, m_dev(NULL)
{
m_GStitleInfoBuffer[0] = 0;
m_interlace = theApp.GetConfig("interlace", 7) % s_interlace_nb;
m_aspectratio = theApp.GetConfig("aspectratio", 1) % s_aspect_ratio_nb;
m_shader = theApp.GetConfig("TVShader", 0) % s_post_shader_nb;
m_filter = theApp.GetConfig("filter", 1);
m_vsync = !!theApp.GetConfig("vsync", 0);
m_aa1 = !!theApp.GetConfig("aa1", 0);
m_fxaa = !!theApp.GetConfig("fxaa", 0);
m_shaderfx = !!theApp.GetConfig("shaderfx", 0);
m_shadeboost = !!theApp.GetConfig("ShadeBoost", 0);
}
GSRenderer::~GSRenderer()
{
/*if(m_dev)
{
m_dev->Reset(1, 1, GSDevice::Windowed);
}*/
delete m_dev;
if (m_wnd)
{
delete m_wnd;
}
}
bool GSRenderer::CreateWnd(const string& title, int w, int h)
{
return m_wnd->Create(title.c_str(), w, h);
}
bool GSRenderer::CreateDevice(GSDevice* dev)
{
ASSERT(dev);
ASSERT(!m_dev);
if(!dev->Create(m_wnd))
{
return false;
}
m_dev = dev;
m_dev->SetVSync(m_vsync && m_framelimit);
return true;
}
void GSRenderer::ResetDevice()
{
if(m_dev) m_dev->Reset(1, 1);
}
bool GSRenderer::Merge(int field)
{
bool en[2];
GSVector4i fr[2];
GSVector4i dr[2];
int baseline = INT_MAX;
for(int i = 0; i < 2; i++)
{
en[i] = IsEnabled(i);
if(en[i])
{
fr[i] = GetFrameRect(i);
dr[i] = GetDisplayRect(i);
baseline = min(dr[i].top, baseline);
//printf("[%d]: %d %d %d %d, %d %d %d %d\n", i, fr[i].x,fr[i].y,fr[i].z,fr[i].w , dr[i].x,dr[i].y,dr[i].z,dr[i].w);
}
}
if(!en[0] && !en[1])
{
return false;
}
GL_PUSH("Renderer Merge %d", s_n);
// try to avoid fullscreen blur, could be nice on tv but on a monitor it's like double vision, hurts my eyes (persona 4, guitar hero)
//
// NOTE: probably the technique explained in graphtip.pdf (Antialiasing by Supersampling / 4. Reading Odd/Even Scan Lines Separately with the PCRTC then Blending)
bool samesrc =
en[0] && en[1] &&
m_regs->DISP[0].DISPFB.FBP == m_regs->DISP[1].DISPFB.FBP &&
m_regs->DISP[0].DISPFB.FBW == m_regs->DISP[1].DISPFB.FBW &&
m_regs->DISP[0].DISPFB.PSM == m_regs->DISP[1].DISPFB.PSM;
// bool blurdetected = false;
if(samesrc /*&& m_regs->PMODE.SLBG == 0 && m_regs->PMODE.MMOD == 1 && m_regs->PMODE.ALP == 0x80*/)
{
if(fr[0].eq(fr[1] + GSVector4i(0, -1, 0, 0)) && dr[0].eq(dr[1] + GSVector4i(0, 0, 0, 1))
|| fr[1].eq(fr[0] + GSVector4i(0, -1, 0, 0)) && dr[1].eq(dr[0] + GSVector4i(0, 0, 0, 1)))
{
// persona 4:
//
// fr[0] = 0 0 640 448
// fr[1] = 0 1 640 448
// dr[0] = 159 50 779 498
// dr[1] = 159 50 779 497
//
// second image shifted up by 1 pixel and blended over itself
//
// god of war:
//
// fr[0] = 0 1 512 448
// fr[1] = 0 0 512 448
// dr[0] = 127 50 639 497
// dr[1] = 127 50 639 498
//
// same just the first image shifted
int top = min(fr[0].top, fr[1].top);
int bottom = max(dr[0].bottom, dr[1].bottom);
fr[0].top = top;
fr[1].top = top;
dr[0].bottom = bottom;
dr[1].bottom = bottom;
// blurdetected = true;
}
else if(dr[0].eq(dr[1]) && (fr[0].eq(fr[1] + GSVector4i(0, 1, 0, 1)) || fr[1].eq(fr[0] + GSVector4i(0, 1, 0, 1))))
{
// dq5:
//
// fr[0] = 0 1 512 445
// fr[1] = 0 0 512 444
// dr[0] = 127 50 639 494
// dr[1] = 127 50 639 494
int top = min(fr[0].top, fr[1].top);
int bottom = min(fr[0].bottom, fr[1].bottom);
fr[0].top = fr[1].top = top;
fr[0].bottom = fr[1].bottom = bottom;
// blurdetected = true;
}
//printf("samesrc = %d blurdetected = %d\n",samesrc,blurdetected);
}
GSVector2i fs(0, 0);
GSVector2i ds(0, 0);
GSTexture* tex[2] = {NULL, NULL};
if(samesrc && fr[0].bottom == fr[1].bottom)
{
tex[0] = GetOutput(0);
tex[1] = tex[0]; // saves one texture fetch
}
else
{
if(en[0]) tex[0] = GetOutput(0);
if(en[1]) tex[1] = GetOutput(1);
}
GSVector4 src[2];
GSVector4 dst[2];
for(int i = 0; i < 2; i++)
{
if(!en[i] || !tex[i]) continue;
GSVector4i r = fr[i];
// overscan hack
if(dr[i].height() > 512) // hmm
{
int y = GetDeviceSize(i).y;
r.bottom = r.top + y;
}
GSVector4 scale = GSVector4(tex[i]->GetScale()).xyxy();
src[i] = GSVector4(r) * scale / GSVector4(tex[i]->GetSize()).xyxy();
GSVector2 off(0, 0);
if(dr[i].top - baseline >= 4) // 2?
{
off.y = tex[i]->GetScale().y * (dr[i].top - baseline);
if(m_regs->SMODE2.INT && m_regs->SMODE2.FFMD)
{
off.y /= 2;
}
}
dst[i] = GSVector4(off).xyxy() + scale * GSVector4(r.rsize());
fs.x = max(fs.x, (int)(dst[i].z + 0.5f));
fs.y = max(fs.y, (int)(dst[i].w + 0.5f));
}
ds = fs;
if(m_regs->SMODE2.INT && m_regs->SMODE2.FFMD)
{
ds.y *= 2;
}
bool slbg = m_regs->PMODE.SLBG;
bool mmod = m_regs->PMODE.MMOD;
if(tex[0] || tex[1])
{
if(tex[0] == tex[1] && !slbg && (src[0] == src[1] & dst[0] == dst[1]).alltrue())
{
// the two outputs are identical, skip drawing one of them (the one that is alpha blended)
tex[0] = NULL;
}
GSVector4 c = GSVector4((int)m_regs->BGCOLOR.R, (int)m_regs->BGCOLOR.G, (int)m_regs->BGCOLOR.B, (int)m_regs->PMODE.ALP) / 255;
m_dev->Merge(tex, src, dst, fs, slbg, mmod, c);
if(m_regs->SMODE2.INT && m_interlace > 0)
{
if (m_interlace == 7 && m_regs->SMODE2.FFMD == 1) // Auto interlace enabled / Odd frame interlace setting
{
int field2 = 0;
int mode = 2;
m_dev->Interlace(ds, field ^ field2, mode, tex[1] ? tex[1]->GetScale().y : tex[0]->GetScale().y);
}
else
{
int field2 = 1 - ((m_interlace - 1) & 1);
int mode = (m_interlace - 1) >> 1;
m_dev->Interlace(ds, field ^ field2, mode, tex[1] ? tex[1]->GetScale().y : tex[0]->GetScale().y);
}
}
if(m_shadeboost)
{
m_dev->ShadeBoost();
}
if (m_shaderfx)
{
m_dev->ExternalFX();
}
if(m_fxaa)
{
m_dev->FXAA();
}
}
GL_POP();
return true;
}
void GSRenderer::SetFrameLimit(bool limit)
{
m_framelimit = limit;
if(m_dev) m_dev->SetVSync(m_vsync && m_framelimit);
}
void GSRenderer::SetVSync(bool enabled)
{
m_vsync = enabled;
if(m_dev) m_dev->SetVSync(m_vsync);
}
void GSRenderer::VSync(int field)
{
GSPerfMonAutoTimer pmat(&m_perfmon);
m_perfmon.Put(GSPerfMon::Frame);
Flush();
if(!m_dev->IsLost(true))
{
if(!Merge(field ? 1 : 0))
{
return;
}
}
else
{
ResetDevice();
}
m_dev->AgePool();
// osd
if((m_perfmon.GetFrame() & 0x1f) == 0)
{
m_perfmon.Update();
double fps = 1000.0f / m_perfmon.Get(GSPerfMon::Frame);
GSVector4i r = GetDisplayRect();
string s;
#ifdef GSTITLEINFO_API_FORCE_VERBOSE
if (1)//force verbose reply
#else
if (m_wnd->IsManaged())
#endif
{
//GSdx owns the window's title, be verbose.
string s2 = m_regs->SMODE2.INT ? (string("Interlaced ") + (m_regs->SMODE2.FFMD ? "(frame)" : "(field)")) : "Progressive";
s = format(
"%lld | %d x %d | %.2f fps (%d%%) | %s - %s | %s | %d S/%d P/%d D | %d%% CPU | %.2f | %.2f",
m_perfmon.GetFrame(), GetInternalResolution().x, GetInternalResolution().y, fps, (int)(100.0 * fps / GetTvRefreshRate()),
s2.c_str(),
theApp.m_gs_interlace[m_interlace].name.c_str(),
theApp.m_gs_aspectratio[m_aspectratio].name.c_str(),
(int)m_perfmon.Get(GSPerfMon::SyncPoint),
(int)m_perfmon.Get(GSPerfMon::Prim),
(int)m_perfmon.Get(GSPerfMon::Draw),
m_perfmon.CPU(),
m_perfmon.Get(GSPerfMon::Swizzle) / 1024,
m_perfmon.Get(GSPerfMon::Unswizzle) / 1024
);
double fillrate = m_perfmon.Get(GSPerfMon::Fillrate);
if(fillrate > 0)
{
s += format(" | %.2f mpps", fps * fillrate / (1024 * 1024));
int sum = 0;
for(int i = 0; i < 16; i++)
{
sum += m_perfmon.CPU(GSPerfMon::WorkerDraw0 + i);
}
s += format(" | %d%% CPU", sum);
}
}
else
{
// Satisfy PCSX2's request for title info: minimal verbosity due to more external title text
s = format("%dx%d | %s", GetInternalResolution().x, GetInternalResolution().y, theApp.m_gs_interlace[m_interlace].name.c_str());
}
if(m_capture.IsCapturing())
{
s += " | Recording...";
}
if(m_wnd->IsManaged())
{
m_wnd->SetWindowText(s.c_str());
}
else
{
// note: do not use TryEnterCriticalSection. It is unnecessary code complication in
// an area that absolutely does not matter (even if it were 100 times slower, it wouldn't
// be noticeable). Besides, these locks are extremely short -- overhead of conditional
// is way more expensive than just waiting for the CriticalSection in 1 of 10,000,000 tries. --air
std::lock_guard<std::mutex> lock(m_pGSsetTitle_Crit);
strncpy(m_GStitleInfoBuffer, s.c_str(), countof(m_GStitleInfoBuffer) - 1);
m_GStitleInfoBuffer[sizeof(m_GStitleInfoBuffer) - 1] = 0; // make sure null terminated even if text overflows
}
}
else
{
// [TODO]
// We don't have window title rights, or the window has no title,
// so let's use actual OSD!
}
if(m_frameskip)
{
return;
}
// present
m_dev->Present(m_wnd->GetClientRect().fit(m_aspectratio), m_shader);
// snapshot
if(!m_snapshot.empty())
{
bool shift = false;
#ifdef _WIN32
shift = !!(::GetAsyncKeyState(VK_SHIFT) & 0x8000);
#else
shift = m_shift_key;
#endif
if(!m_dump && shift)
{
GSFreezeData fd;
fd.size = 0;
fd.data = NULL;
Freeze(&fd, true);
fd.data = new uint8[fd.size];
Freeze(&fd, false);
m_dump.Open(m_snapshot, m_crc, fd, m_regs);
delete [] fd.data;
}
if(GSTexture* t = m_dev->GetCurrent())
{
t->Save(m_snapshot + ".bmp", true);
}
m_snapshot.clear();
}
else
{
if(m_dump)
{
bool control = false;
#ifdef _WIN32
control = !!(::GetAsyncKeyState(VK_CONTROL) & 0x8000);
#else
control = m_control_key;
#endif
m_dump.VSync(field, !control, m_regs);
}
}
// capture
if(m_capture.IsCapturing())
{
if(GSTexture* current = m_dev->GetCurrent())
{
GSVector2i size = m_capture.GetSize();
if(GSTexture* offscreen = m_dev->CopyOffscreen(current, GSVector4(0, 0, 1, 1), size.x, size.y))
{
GSTexture::GSMap m;
if(offscreen->Map(m))
{
m_capture.DeliverFrame(m.bits, m.pitch, !m_dev->IsRBSwapped());
offscreen->Unmap();
}
m_dev->Recycle(offscreen);
}
}
}
}
bool GSRenderer::MakeSnapshot(const string& path)
{
if(m_snapshot.empty())
{
time_t t = time(NULL);
char buff[16];
if(strftime(buff, sizeof(buff), "%Y%m%d%H%M%S", localtime(&t)))
{
m_snapshot = format("%s_%s", path.c_str(), buff);
}
}
return true;
}
bool GSRenderer::BeginCapture()
{
GSVector4i disp = m_wnd->GetClientRect().fit(m_aspectratio);
float aspect = (float)disp.width() / max(1, disp.height());
return m_capture.BeginCapture(GetTvRefreshRate(), GetInternalResolution(), aspect);
}
void GSRenderer::EndCapture()
{
m_capture.EndCapture();
}
void GSRenderer::KeyEvent(GSKeyEventData* e)
{
#ifdef _WIN32
if(e->type == KEYPRESS)
{
int step = (::GetAsyncKeyState(VK_SHIFT) & 0x8000) ? -1 : 1;
switch(e->key)
{
case VK_F5:
m_interlace = (m_interlace + s_interlace_nb + step) % s_interlace_nb;
printf("GSdx: Set deinterlace mode to %d (%s).\n", (int)m_interlace, theApp.m_gs_interlace.at(m_interlace).name.c_str());
return;
case VK_F6:
if( m_wnd->IsManaged() )
m_aspectratio = (m_aspectratio + s_aspect_ratio_nb + step) % s_aspect_ratio_nb;
return;
case VK_F7:
m_shader = (m_shader + s_post_shader_nb + step) % s_post_shader_nb;
printf("GSdx: Set shader to: %d.\n", (int)m_shader);
return;
case VK_DELETE:
m_aa1 = !m_aa1;
printf("GSdx: (Software) Edge anti-aliasing is now %s.\n", m_aa1 ? "enabled" : "disabled");
return;
case VK_INSERT:
m_mipmap = !m_mipmap;
printf("GSdx: (Software) Mipmapping is now %s.\n", m_mipmap ? "enabled" : "disabled");
return;
case VK_PRIOR:
m_fxaa = !m_fxaa;
printf("GSdx: FXAA anti-aliasing is now %s.\n", m_fxaa ? "enabled" : "disabled");
return;
case VK_HOME:
m_shaderfx = !m_shaderfx;
printf("GSdx: External post-processing is now %s.\n", m_shaderfx ? "enabled" : "disabled");
return;
}
}
#elif defined(__linux__)
if(e->type == KEYPRESS)
{
int step = m_shift_key ? -1 : 1;
switch(e->key)
{
case XK_F5:
m_interlace = (m_interlace + s_interlace_nb + step) % s_interlace_nb;
printf("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 + s_aspect_ratio_nb + step) % s_aspect_ratio_nb;
return;
case XK_F7:
m_shader = (m_shader + s_post_shader_nb + step) % s_post_shader_nb;
printf("GSdx: Set shader %d.\n", (int)m_shader);
return;
case XK_Delete:
m_aa1 = !m_aa1;
printf("GSdx: (Software) Edge anti-aliasing is now %s.\n", m_aa1 ? "enabled" : "disabled");
return;
case XK_Insert:
m_mipmap = !m_mipmap;
printf("GSdx: (Software) Mipmapping is now %s.\n", m_mipmap ? "enabled" : "disabled");
return;
case XK_Prior:
m_fxaa = !m_fxaa;
printf("GSdx: FXAA anti-aliasing is now %s.\n", m_fxaa ? "enabled" : "disabled");
return;
case XK_Home:
m_shaderfx = !m_shaderfx;
printf("GSdx: External post-processing is now %s.\n", m_shaderfx ? "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

@ -0,0 +1,86 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSdx.h"
#include "GSWnd.h"
#include "GSState.h"
#include "GSCapture.h"
class GSRenderer : public GSState
{
GSCapture m_capture;
string m_snapshot;
int m_shader;
bool Merge(int field);
// Only used on linux
bool m_shift_key;
bool m_control_key;
protected:
int m_interlace;
int m_aspectratio;
int m_filter;
bool m_vsync;
bool m_aa1;
bool m_framelimit;
bool m_shaderfx;
bool m_fxaa;
bool m_shadeboost;
bool m_texture_shuffle;
virtual GSTexture* GetOutput(int i) = 0;
public:
GSWnd* m_wnd;
GSDevice* m_dev;
public:
GSRenderer();
virtual ~GSRenderer();
virtual bool CreateWnd(const string& title, int w, int h);
virtual bool CreateDevice(GSDevice* dev);
virtual void ResetDevice();
virtual void VSync(int field);
virtual bool MakeSnapshot(const string& path);
virtual void KeyEvent(GSKeyEventData* e);
virtual bool CanUpscale() {return false;}
virtual int GetUpscaleMultiplier() {return 1;}
virtual GSVector2i GetInternalResolution() {
return GSVector2i(GetDisplayRect().width(), GetDisplayRect().height());
}
void SetAspectRatio(int aspect) {m_aspectratio = aspect;}
void SetVSync(bool enabled);
void SetFrameLimit(bool limit);
virtual void SetExclusive(bool isExcl) {}
virtual bool BeginCapture();
virtual void EndCapture();
public:
std::mutex m_pGSsetTitle_Crit;
char m_GStitleInfoBuffer[128];
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,268 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSRenderer.h"
#ifdef ENABLE_OPENCL
__aligned(struct, 32) GSVertexCL
{
GSVector4 p, t;
};
class GSRendererCL : public GSRenderer
{
typedef void (GSRendererCL::*ConvertVertexBufferPtr)(GSVertexCL* RESTRICT dst, const GSVertex* RESTRICT src, size_t count);
ConvertVertexBufferPtr m_cvb[4][2][2];
template<uint32 primclass, uint32 tme, uint32 fst>
void ConvertVertexBuffer(GSVertexCL* RESTRICT dst, const GSVertex* RESTRICT src, size_t count);
union PrimSelector
{
struct
{
uint32 prim:2; // 0
};
uint32 key;
operator uint32() const { return key; }
};
union TileSelector
{
struct
{
uint32 prim:2; // 0
uint32 mode:2; // 2
uint32 clear:1; // 4
};
uint32 key;
operator uint32() const { return key; }
};
union TFXSelector
{
struct
{
uint32 fpsm:3; // 0
uint32 zpsm:3; // 3
uint32 ztst:2; // 6 (0: off, 1: write, 2: test (ge), 3: test (g))
uint32 atst:3; // 8
uint32 afail:2; // 11
uint32 iip:1; // 13
uint32 tfx:3; // 14
uint32 tcc:1; // 17
uint32 fst:1; // 18
uint32 ltf:1; // 19
uint32 tlu:1; // 20
uint32 fge:1; // 21
uint32 date:1; // 22
uint32 abe:1; // 23
uint32 aba:2; // 24
uint32 abb:2; // 26
uint32 abc:2; // 28
uint32 abd:2; // 30
uint32 pabe:1; // 32
uint32 aa1:1; // 33
uint32 fwrite:1; // 34
uint32 ftest:1; // 35
uint32 rfb:1; // 36
uint32 zwrite:1; // 37
uint32 ztest:1; // 38
uint32 rzb:1; // 39
uint32 wms:2; // 40
uint32 wmt:2; // 42
uint32 datm:1; // 44
uint32 colclamp:1; // 45
uint32 fba:1; // 46
uint32 dthe:1; // 47
uint32 prim:2; // 48
uint32 lcm:1; // 50
uint32 mmin:2; // 51
uint32 noscissor:1; // 53
uint32 tpsm:4; // 54
uint32 aem:1; // 58
uint32 merged:1; // 59
// TODO
};
struct
{
uint32 _pad1:24;
uint32 ababcd:8;
uint32 _pad2:2;
uint32 fb:2;
uint32 _pad3:1;
uint32 zb:2;
};
struct
{
uint32 lo;
uint32 hi;
};
uint64 key;
operator uint64() const { return key; }
bool IsSolidRect() const
{
return prim == GS_SPRITE_CLASS
&& iip == 0
&& tfx == TFX_NONE
&& abe == 0
&& ztst <= 1
&& atst <= 1
&& date == 0
&& fge == 0;
}
};
__aligned(struct, 32) TFXParameter
{
GSVector4i scissor;
GSVector4i dimx; // 4x4 signed char
TFXSelector sel;
uint32 fbp, zbp, bw;
uint32 fm, zm;
uint32 fog; // rgb
uint8 aref, afix;
uint8 ta0, ta1;
uint32 tbp[7], tbw[7];
int minu, maxu, minv, maxv; // umsk, ufix, vmsk, vfix
int lod; // lcm == 1
int mxl;
float l; // TEX1.L * -0x10000
float k; // TEX1.K * 0x10000
uint32 clut[256];
};
class TFXJob
{
public:
struct { int x, y, z, w; } rect;
TFXSelector sel;
uint32 ib_start;
uint32 prim_count;
GSVector4i* src_pages; // read by any texture level
GSVector4i* dst_pages; // f/z writes to it
uint32 fbp, zbp, bw;
uint32 fpsm, zpsm, tpsm;
#ifdef DEBUG
TFXParameter* pb;
#endif
TFXJob();
virtual ~TFXJob();
GSVector4i* GetSrcPages();
GSVector4i* GetDstPages();
};
class CL
{
std::string kernel_str;
std::map<uint32, cl::Kernel> prim_map;
std::map<uint32, cl::Kernel> tile_map;
std::map<uint64, cl::Kernel> tfx_map;
cl::Kernel Build(const char* entry, ostringstream& opt);
void AddDefs(ostringstream& opt);
public:
std::vector<OCLDeviceDesc> devs;
cl::Context context;
cl::CommandQueue queue[3];
cl::Buffer vm;
cl::Buffer tex;
struct { cl::Buffer buff[2]; size_t head, tail, size; unsigned char* ptr; void* mapped_ptr; } vb, ib, pb;
cl::Buffer env;
cl::CommandQueue* wq;
int wqidx;
uint32 WIs;
int version;
public:
CL();
virtual ~CL();
cl::Kernel& GetPrimKernel(const PrimSelector& sel);
cl::Kernel& GetTileKernel(const TileSelector& sel);
cl::Kernel& GetTFXKernel(const TFXSelector& sel);
void Map();
void Unmap();
};
CL m_cl;
std::list<shared_ptr<TFXJob>> m_jobs;
uint32 m_vb_start;
uint32 m_vb_count;
uint32 m_pb_start;
uint32 m_pb_count;
bool m_synced;
void Enqueue();
void EnqueueTFX(std::list<shared_ptr<TFXJob>>& jobs, uint32 bin_count, const cl_uchar4& bin_dim);
void JoinTFX(std::list<shared_ptr<TFXJob>>& jobs);
bool UpdateTextureCache(TFXJob* job);
void InvalidateTextureCache(TFXJob* job);
void UsePages(uint32* pages);
void ReleasePages(uint32* pages);
static void CL_CALLBACK ReleasePageEvent(cl_event event, cl_int event_command_exec_status, void* user_data);
protected:
GSTexture* m_texture[2];
uint8* m_output;
GSVector4i m_rw_pages[2][4]; // pages that may be read or modified by the rendering queue, f/z rw, tex r
GSVector4i m_tc_pages[4]; // invalidated texture cache pages (split this into 8:24?) // TODO: this should be block level, too many overlaps inside pages with render targets
GSVector4i m_tmp_pages[4];
uint32 m_tmp_pages2[MAX_PAGES + 1];
uint32 m_rw_pages_rendering[512]; // pages that are currently in-use
void Reset();
void VSync(int field);
void ResetDevice();
GSTexture* GetOutput(int i);
void Draw();
void Sync(int reason);
void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r);
void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r, bool clut = false);
bool SetupParameter(TFXJob* job, TFXParameter* pb, GSVertexCL* vertex, size_t vertex_count, const uint32* index, size_t index_count);
public:
GSRendererCL();
virtual ~GSRendererCL();
};
#endif

View File

@ -0,0 +1,877 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSRendererCS.h"
#define PS_BATCH_SIZE 512
GSRendererCS::GSRendererCS()
: GSRenderer()
{
m_nativeres = true;
memset(m_vm_valid, 0, sizeof(m_vm_valid));
memset(m_texture, 0, sizeof(m_texture));
m_output = (uint8*)_aligned_malloc(1024 * 1024 * sizeof(uint32), 32);
}
GSRendererCS::~GSRendererCS()
{
for(size_t i = 0; i < countof(m_texture); i++)
{
delete m_texture[i];
}
_aligned_free(m_output);
}
bool GSRendererCS::CreateDevice(GSDevice* dev_unk)
{
if(!__super::CreateDevice(dev_unk))
return false;
HRESULT hr;
D3D11_DEPTH_STENCIL_DESC dsd;
D3D11_BLEND_DESC bsd;
D3D11_SAMPLER_DESC sd;
D3D11_BUFFER_DESC bd;
D3D11_TEXTURE2D_DESC td;
D3D11_UNORDERED_ACCESS_VIEW_DESC uavd;
D3D11_SHADER_RESOURCE_VIEW_DESC srvd;
D3D_FEATURE_LEVEL level;
((GSDeviceDX*)dev_unk)->GetFeatureLevel(level);
if(level < D3D_FEATURE_LEVEL_11_0)
return false;
GSDevice11* dev = (GSDevice11*)dev_unk;
ID3D11DeviceContext* ctx = *dev;
// empty depth stencil state
memset(&dsd, 0, sizeof(dsd));
dsd.StencilEnable = false;
dsd.DepthEnable = false;
hr = (*dev)->CreateDepthStencilState(&dsd, &m_dss);
if(FAILED(hr)) return false;
// empty blend state
memset(&bsd, 0, sizeof(bsd));
bsd.RenderTarget[0].BlendEnable = false;
hr = (*dev)->CreateBlendState(&bsd, &m_bs);
if(FAILED(hr)) return false;
// point sampler
memset(&sd, 0, sizeof(sd));
sd.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
sd.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
sd.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
sd.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
sd.MinLOD = -FLT_MAX;
sd.MaxLOD = FLT_MAX;
sd.MaxAnisotropy = theApp.GetConfig("MaxAnisotropy", 0);
sd.ComparisonFunc = D3D11_COMPARISON_NEVER;
hr = (*dev)->CreateSamplerState(&sd, &m_ss);
if(FAILED(hr)) return false;
// link buffer
memset(&bd, 0, sizeof(bd));
bd.ByteWidth = 256 << 20; // 256 MB w00t
bd.StructureByteStride = sizeof(uint32) * 4; // c, z, id, next
bd.Usage = D3D11_USAGE_DEFAULT;
bd.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
bd.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
hr = (*dev)->CreateBuffer(&bd, NULL, &m_lb);
{
uint32 data[] = {0, 0, 0xffffffff, 0};
D3D11_BOX box;
memset(&box, 0, sizeof(box));
box.right = sizeof(data);
box.bottom = 1;
box.back = 1;
ctx->UpdateSubresource(m_lb, 0, &box, data, 0, 0);
}
if(FAILED(hr)) return false;
memset(&uavd, 0, sizeof(uavd));
uavd.Format = DXGI_FORMAT_UNKNOWN;
uavd.Buffer.NumElements = bd.ByteWidth / bd.StructureByteStride;
uavd.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_COUNTER;
uavd.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
hr = (*dev)->CreateUnorderedAccessView(m_lb, &uavd, &m_lb_uav);
if(FAILED(hr)) return false;
memset(&srvd, 0, sizeof(srvd));
srvd.Format = DXGI_FORMAT_UNKNOWN;
srvd.Buffer.NumElements = bd.ByteWidth / bd.StructureByteStride;
srvd.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
hr = (*dev)->CreateShaderResourceView(m_lb, &srvd, &m_lb_srv);
if(FAILED(hr)) return false;
// start offset buffer
memset(&bd, 0, sizeof(bd));
bd.ByteWidth = sizeof(uint32) * 2048 * 2048; // index
bd.Usage = D3D11_USAGE_DEFAULT;
bd.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
bd.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
hr = (*dev)->CreateBuffer(&bd, NULL, &m_sob);
if(FAILED(hr)) return false;
memset(&uavd, 0, sizeof(uavd));
uavd.Format = DXGI_FORMAT_R32_TYPELESS;
uavd.Buffer.NumElements = bd.ByteWidth / sizeof(uint32);
uavd.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW;
uavd.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
hr = (*dev)->CreateUnorderedAccessView(m_sob, &uavd, &m_sob_uav);
if(FAILED(hr)) return false;
memset(&srvd, 0, sizeof(srvd));
srvd.Format = DXGI_FORMAT_R32_TYPELESS;
srvd.BufferEx.NumElements = bd.ByteWidth / sizeof(uint32);
srvd.BufferEx.Flags = D3D11_BUFFEREX_SRV_FLAG_RAW;
srvd.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX;
hr = (*dev)->CreateShaderResourceView(m_sob, &srvd, &m_sob_srv);
if(FAILED(hr)) return false;
const uint32 tmp = 0;
ctx->ClearUnorderedAccessViewUint(m_sob_uav, &tmp); // initial clear, next time Draw should restore it in Step 2
// video memory (4MB)
memset(&bd, 0, sizeof(bd));
bd.ByteWidth = 4 * 1024 * 1024;
bd.Usage = D3D11_USAGE_DEFAULT;
bd.BindFlags = D3D11_BIND_UNORDERED_ACCESS;
bd.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
hr = (*dev)->CreateBuffer(&bd, NULL, &m_vm);
if(FAILED(hr)) return false;
memset(&uavd, 0, sizeof(uavd));
uavd.Format = DXGI_FORMAT_R32_TYPELESS;
uavd.Buffer.FirstElement = 0;
uavd.Buffer.NumElements = 1024 * 1024;
uavd.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW;
uavd.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
hr = (*dev)->CreateUnorderedAccessView(m_vm, &uavd, &m_vm_uav);
if(FAILED(hr)) return false;
/*
memset(&td, 0, sizeof(td));
td.Width = PAGE_SIZE;
td.Height = MAX_PAGES;
td.Format = DXGI_FORMAT_R8_UINT;
td.MipLevels = 1;
td.ArraySize = 1;
td.SampleDesc.Count = 1;
td.SampleDesc.Quality = 0;
td.Usage = D3D11_USAGE_DEFAULT;
td.BindFlags = D3D11_BIND_UNORDERED_ACCESS;
hr = (*dev)->CreateTexture2D(&td, NULL, &m_vm);
if(FAILED(hr)) return false;
memset(&uavd, 0, sizeof(uavd));
uavd.Format = DXGI_FORMAT_R8_UINT;
uavd.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D;
hr = (*dev)->CreateUnorderedAccessView(m_vm, &uavd, &m_vm_uav);
if(FAILED(hr)) return false;
*/
// one page, for copying between cpu<->gpu
memset(&bd, 0, sizeof(bd));
bd.ByteWidth = PAGE_SIZE;
bd.Usage = D3D11_USAGE_STAGING;
bd.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
hr = (*dev)->CreateBuffer(&bd, NULL, &m_pb);
if(FAILED(hr)) return false;
/*
memset(&td, 0, sizeof(td));
td.Width = PAGE_SIZE;
td.Height = 1;
td.Format = DXGI_FORMAT_R8_UINT;
td.MipLevels = 1;
td.ArraySize = 1;
td.SampleDesc.Count = 1;
td.SampleDesc.Quality = 0;
td.Usage = D3D11_USAGE_STAGING;
td.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
hr = (*dev)->CreateTexture2D(&td, NULL, &m_pb);
if(FAILED(hr)) return false;
*/
// VSConstantBuffer
memset(&bd, 0, sizeof(bd));
bd.ByteWidth = sizeof(VSConstantBuffer);
bd.Usage = D3D11_USAGE_DEFAULT;
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
hr = (*dev)->CreateBuffer(&bd, NULL, &m_vs_cb);
if(FAILED(hr)) return false;
// PS
D3D_SHADER_MACRO macro[] =
{
{NULL, NULL},
};
try
{
vector<unsigned char> shader;
theApp.LoadResource(IDR_CS_FX, shader);
dev->CompileShader((const char *)shader.data(), shader.size(), "cs.fx", nullptr, "ps_main0", macro, &m_ps0);
}
catch (GSDXRecoverableError)
{
return false;
}
// PSConstantBuffer
memset(&bd, 0, sizeof(bd));
bd.ByteWidth = sizeof(PSConstantBuffer);
bd.Usage = D3D11_USAGE_DEFAULT;
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
hr = (*dev)->CreateBuffer(&bd, NULL, &m_ps_cb);
if(FAILED(hr)) return false;
//
return true;
}
void GSRendererCS::ResetDevice()
{
for(size_t i = 0; i < countof(m_texture); i++)
{
delete m_texture[i];
m_texture[i] = NULL;
}
}
void GSRendererCS::VSync(int field)
{
__super::VSync(field);
//printf("%lld\n", m_perfmon.GetFrame());
}
GSTexture* GSRendererCS::GetOutput(int i)
{
// TODO: create a compute shader which unswizzles the frame from m_vm to the output texture
const GSRegDISPFB& DISPFB = m_regs->DISP[i].DISPFB;
int w = DISPFB.FBW * 64;
int h = GetFrameRect(i).bottom;
// TODO: round up bottom
if(m_dev->ResizeTexture(&m_texture[i], w, h))
{
const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[DISPFB.PSM];
GSVector4i r(0, 0, w, h);
GSVector4i r2 = r.ralign<Align_Outside>(psm.bs);
GSOffset* off = m_mem.GetOffset(DISPFB.Block(), DISPFB.FBW, DISPFB.PSM);
Read(off, r2, false);
(m_mem.*psm.rtx)(off, r2, m_output, 1024 * 4, m_env.TEXA);
m_texture[i]->Update(r, m_output, 1024 * 4);
if(s_dump)
{
if(s_save && s_n >= s_saven)
{
m_texture[i]->Save(format("c:\\temp1\\_%05d_f%lld_fr%d_%05x_%d.bmp", s_n, m_perfmon.GetFrame(), i, (int)DISPFB.Block(), (int)DISPFB.PSM));
}
s_n++;
}
}
return m_texture[i];
}
void GSRendererCS::Draw()
{
GSDrawingEnvironment& env = m_env;
GSDrawingContext* context = m_context;
GSVector2i rtsize(2048, 2048);
GSVector4i scissor = GSVector4i(context->scissor.in).rintersect(GSVector4i(rtsize).zwxy());
GSVector4i bbox = GSVector4i(m_vt.m_min.p.floor().xyxy(m_vt.m_max.p.ceil()));
GSVector4i r = bbox.rintersect(scissor);
uint32 fm = context->FRAME.FBMSK;
uint32 zm = context->ZBUF.ZMSK || context->TEST.ZTE == 0 ? 0xffffffff : 0;
if(fm != 0xffffffff)
{
Write(context->offset.fb, r);
// TODO: m_tc->InvalidateVideoMem(context->offset.fb, r, false);
}
if(zm != 0xffffffff)
{
Write(context->offset.zb, r);
// TODO: m_tc->InvalidateVideoMem(context->offset.zb, r, false);
}
// TODO: if(24-bit) fm/zm |= 0xff000000;
if(PRIM->TME)
{
m_mem.m_clut.Read32(context->TEX0, env.TEXA);
GSVector4i r;
GetTextureMinMax(r, context->TEX0, context->CLAMP, m_vt.IsLinear());
// TODO: unswizzle pages of r to a texture, check m_vm_valid, bit not set cpu->gpu, set gpu->gpu
// TODO: Write transfer should directly write to m_vm, then Read/Write syncing won't be necessary, clut must be updated with the gpu also
// TODO: tex = m_tc->LookupSource(context->TEX0, env.TEXA, r);
// if(!tex) return;
}
//
GSDevice11* dev = (GSDevice11*)m_dev;
ID3D11DeviceContext* ctx = *dev;
//
dev->BeginScene();
// SetupOM
dev->OMSetDepthStencilState(m_dss, 0);
dev->OMSetBlendState(m_bs, 0);
ID3D11UnorderedAccessView* uavs[] = {m_vm_uav, m_lb_uav, m_sob_uav};
uint32 counters[] = {1, 0, 0};
dev->OMSetRenderTargets(rtsize, countof(uavs), uavs, counters, &scissor);
// SetupIA
D3D11_PRIMITIVE_TOPOLOGY topology;
switch(m_vt.m_primclass)
{
case GS_POINT_CLASS:
topology = D3D11_PRIMITIVE_TOPOLOGY_POINTLIST;
break;
case GS_LINE_CLASS:
case GS_SPRITE_CLASS:
topology = D3D11_PRIMITIVE_TOPOLOGY_LINELIST;
break;
case GS_TRIANGLE_CLASS:
topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
break;
default:
__assume(0);
}
GSVector4i r2 = bbox.add32(GSVector4i(-1, -1, 1, 1)).rintersect(scissor);
m_vertex.buff[m_vertex.next + 0].XYZ.X = (uint16)(context->XYOFFSET.OFX + (r2.left << 4));
m_vertex.buff[m_vertex.next + 0].XYZ.Y = (uint16)(context->XYOFFSET.OFY + (r2.top << 4));
m_vertex.buff[m_vertex.next + 1].XYZ.X = (uint16)(context->XYOFFSET.OFX + (r2.right << 4));
m_vertex.buff[m_vertex.next + 1].XYZ.Y = (uint16)(context->XYOFFSET.OFY + (r2.bottom << 4));
m_index.buff[m_index.tail + 0] = m_vertex.next + 0;
m_index.buff[m_index.tail + 1] = m_vertex.next + 1;
dev->IASetVertexBuffer(m_vertex.buff, sizeof(GSVertex), m_vertex.next + 2);
dev->IASetIndexBuffer(m_index.buff, m_index.tail + 2);
// SetupVS
VSSelector vs_sel;
vs_sel.tme = PRIM->TME;
vs_sel.fst = PRIM->FST;
VSConstantBuffer vs_cb;
float sx = 2.0f / (rtsize.x << 4);
float sy = 2.0f / (rtsize.y << 4);
//float sx = 1.0f / 16;
//float sy = 1.0f / 16;
float ox = (float)(int)context->XYOFFSET.OFX;
float oy = (float)(int)context->XYOFFSET.OFY;
vs_cb.VertexScale = GSVector4(sx, -sy, 0.0f, 0.0f);
vs_cb.VertexOffset = GSVector4(ox * sx + 1, -(oy * sy + 1), 0.0f, -1.0f);
//vs_cb.VertexScale = GSVector4(sx, sy, 0.0f, 0.0f);
//vs_cb.VertexOffset = GSVector4(ox * sx, oy * sy, 0.0f, -1.0f);
{
GSVertexShader11 vs;
hash_map<uint32, GSVertexShader11>::const_iterator i = m_vs.find(vs_sel);
if(i != m_vs.end())
{
vs = i->second;
}
else
{
string str[2];
str[0] = format("%d", vs_sel.tme);
str[1] = format("%d", vs_sel.fst);
D3D_SHADER_MACRO macro[] =
{
{"VS_TME", str[0].c_str()},
{"VS_FST", str[1].c_str()},
{NULL, NULL},
};
D3D11_INPUT_ELEMENT_DESC layout[] =
{
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"TEXCOORD", 1, DXGI_FORMAT_R32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"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},
{"TEXCOORD", 2, DXGI_FORMAT_R16G16_UINT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"COLOR", 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0},
};
vector<unsigned char> shader;
theApp.LoadResource(IDR_CS_FX, shader);
dev->CompileShader((const char *)shader.data(), shader.size(), "cs.fx", nullptr, "vs_main", macro, &vs.vs, layout, countof(layout), &vs.il);
m_vs[vs_sel] = vs;
}
ctx->UpdateSubresource(m_vs_cb, 0, NULL, &vs_cb, 0, 0); // TODO: only update if changed
dev->VSSetShader(vs.vs, m_vs_cb);
dev->IASetInputLayout(vs.il);
}
// SetupGS
GSSelector gs_sel;
gs_sel.iip = PRIM->IIP;
CComPtr<ID3D11GeometryShader> gs[2];
for(int j = 0; j < 2; j++)
{
gs_sel.prim = j == 0 ? m_vt.m_primclass : GS_SPRITE_CLASS;
hash_map<uint32, CComPtr<ID3D11GeometryShader> >::const_iterator i = m_gs.find(gs_sel);
if(i != m_gs.end())
{
gs[j] = i->second;
}
else
{
string str[2];
str[0] = format("%d", gs_sel.iip);
str[1] = format("%d", j == 0 ? gs_sel.prim : GS_SPRITE_CLASS);
D3D_SHADER_MACRO macro[] =
{
{"GS_IIP", str[0].c_str()},
{"GS_PRIM", str[1].c_str()},
{NULL, NULL},
};
vector<unsigned char> shader;
theApp.LoadResource(IDR_CS_FX, shader);
dev->CompileShader((const char *)shader.data(), shader.size(), "cs.fx", nullptr, "gs_main", macro, &gs[j]);
m_gs[gs_sel] = gs[j];
}
}
// SetupPS
dev->PSSetSamplerState(m_ss, NULL, NULL);
PSSelector ps_sel;
ps_sel.fpsm = context->FRAME.PSM;
ps_sel.zpsm = context->ZBUF.PSM;
CComPtr<ID3D11PixelShader> ps[2] = {m_ps0, NULL};
hash_map<uint32, CComPtr<ID3D11PixelShader> >::const_iterator i = m_ps1.find(ps_sel);
if(i != m_ps1.end())
{
ps[1] = i->second;
}
else
{
string str[15];
str[0] = format("%d", PS_BATCH_SIZE);
str[1] = format("%d", context->FRAME.PSM);
str[2] = format("%d", context->ZBUF.PSM);
D3D_SHADER_MACRO macro[] =
{
{"PS_BATCH_SIZE", str[0].c_str()},
{"PS_FPSM", str[1].c_str()},
{"PS_ZPSM", str[2].c_str()},
{NULL, NULL},
};
vector<unsigned char> shader;
theApp.LoadResource(IDR_CS_FX, shader);
dev->CompileShader((const char *)shader.data(), shader.size(), "cs.fx", nullptr, "ps_main1", macro, &ps[1]);
m_ps1[ps_sel] = ps[1];
}
PSConstantBuffer ps_cb;
ps_cb.fm = fm;
ps_cb.zm = zm;
ctx->UpdateSubresource(m_ps_cb, 0, NULL, &ps_cb, 0, 0); // TODO: only update if changed
OffsetBuffer* fzbo = NULL;
GetOffsetBuffer(&fzbo);
dev->PSSetShaderResourceView(0, fzbo->row_srv);
dev->PSSetShaderResourceView(1, fzbo->col_srv);
// TODO: palette, texture
int step = PS_BATCH_SIZE * GSUtil::GetVertexCount(PRIM->PRIM);
for(uint32 i = 0; i < m_index.tail; i += step)
{
dev->IASetPrimitiveTopology(topology);
dev->GSSetShader(gs[0]);
dev->PSSetShader(ps[0], m_ps_cb);
dev->DrawIndexedPrimitive(i, std::min<int>(m_index.tail - i, step));
dev->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
dev->GSSetShader(gs[1]);
dev->PSSetShader(ps[1], m_ps_cb);
dev->DrawIndexedPrimitive(m_index.tail, 2);
//printf("%d/%d, %d %d %d %d\n", i, m_index.tail, r2.x, r2.y, r2.z, r2.w);
}
dev->EndScene();
if(0)
{
std::string s;
/*
s = format("c:\\temp1\\_%05d_f%lld_fb0_%05x_%d.bmp", s_n, m_perfmon.GetFrame(), 0, 0);
m_mem.SaveBMP(s, 0, 16, PSM_PSMCT32, 1024, 1024);
Read(m_mem.GetOffset(0, 16, PSM_PSMCT32), GSVector4i(0, 0, 1024, 1024), false);
*/
//
if(fm != 0xffffffff) Read(context->offset.fb, r, false);
//
if(zm != 0xffffffff) Read(context->offset.zb, r, false);
s = format("c:\\temp1\\_%05d_f%lld_rt1_%05x_%d.bmp", s_n, m_perfmon.GetFrame(), m_context->FRAME.Block(), m_context->FRAME.PSM);
m_mem.SaveBMP(s, m_context->FRAME.Block(), m_context->FRAME.FBW, m_context->FRAME.PSM, GetFrameRect().width(), 512);
s = format("c:\\temp1\\_%05d_f%lld_zt1_%05x_%d.bmp", s_n, m_perfmon.GetFrame(), m_context->ZBUF.Block(), m_context->ZBUF.PSM);
m_mem.SaveBMP(s, m_context->ZBUF.Block(), m_context->FRAME.FBW, m_context->ZBUF.PSM, GetFrameRect().width(), 512);
/*
s = format("c:\\temp1\\_%05d_f%lld_fb1_%05x_%d.bmp", s_n, m_perfmon.GetFrame(), 0, 0);
m_mem.SaveBMP(s, 0, 16, PSM_PSMCT32, 1024, 1024);
*/
s_n++;
}
}
void GSRendererCS::InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r)
{
GSOffset* off = m_mem.GetOffset(BITBLTBUF.DBP, BITBLTBUF.DBW, BITBLTBUF.DPSM);
Read(off, r, true); // TODO: fully overwritten pages are not needed to be read, only invalidated (important)
// TODO: false deps, 8H/4HL/4HH texture sharing pages with 24-bit target
// TODO: invalidate texture cache
}
void GSRendererCS::InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r, bool clut)
{
GSOffset* off = m_mem.GetOffset(BITBLTBUF.SBP, BITBLTBUF.SBW, BITBLTBUF.SPSM);
Read(off, r, false);
}
void GSRendererCS::Write(GSOffset* off, const GSVector4i& r)
{
GSDevice11* dev = (GSDevice11*)m_dev;
ID3D11DeviceContext* ctx = *dev;
D3D11_BOX box;
memset(&box, 0, sizeof(box));
box.right = 1;
box.bottom = 1;
box.back = 1;
uint32* pages = off->GetPages(r);
for(size_t i = 0; pages[i] != GSOffset::EOP; i++)
{
uint32 page = pages[i];
uint32 row = page >> 5;
uint32 col = 1 << (page & 31);
if((m_vm_valid[row] & col) == 0)
{
m_vm_valid[row] |= col;
box.left = page * PAGE_SIZE;
box.right = (page + 1) * PAGE_SIZE;
ctx->UpdateSubresource(m_vm, 0, &box, m_mem.m_vm8 + page * PAGE_SIZE, 0, 0);
/*
// m_vm texture row is 2k in bytes, one page is 8k => starting row: addr / 4k, number of rows: 8k / 2k = 4
box.left = 0;
box.right = PAGE_SIZE;
box.top = page;
box.bottom = box.top + 1;
ctx->UpdateSubresource(m_vm, 0, &box, m_mem.m_vm8 + page * PAGE_SIZE, 0, 0);
*/
if(0)
printf("[%lld] write %05x %d %d (%d)\n", __rdtsc(), off->bp, off->bw, off->psm, page);
}
}
delete [] pages;
}
void GSRendererCS::Read(GSOffset* off, const GSVector4i& r, bool invalidate)
{
GSDevice11* dev = (GSDevice11*)m_dev;
ID3D11DeviceContext* ctx = *dev;
D3D11_BOX box;
memset(&box, 0, sizeof(box));
box.right = 1;
box.bottom = 1;
box.back = 1;
uint32* pages = off->GetPages(r);
for(size_t i = 0; pages[i] != GSOffset::EOP; i++)
{
uint32 page = pages[i];
uint32 row = page >> 5;
uint32 col = 1 << (page & 31);
if(m_vm_valid[row] & col)
{
if(invalidate)
{
m_vm_valid[row] ^= col;
}
box.left = page * PAGE_SIZE;
box.right = (page + 1) * PAGE_SIZE;
ctx->CopySubresourceRegion(m_pb, 0, 0, 0, 0, m_vm, 0, &box);
/*
// m_vm texture row is 2k in bytes, one page is 8k => starting row: addr / 4k, number of rows: 8k / 2k = 4
box.left = 0;
box.right = PAGE_SIZE;
box.top = page;
box.bottom = box.top + 1;
ctx->CopySubresourceRegion(m_pb, 0, 0, 0, 0, m_vm, 0, &box);
*/
D3D11_MAPPED_SUBRESOURCE map;
if(SUCCEEDED(ctx->Map(m_pb, 0, D3D11_MAP_READ, 0, &map)))
{
memcpy(m_mem.m_vm8 + page * PAGE_SIZE, map.pData, PAGE_SIZE);
ctx->Unmap(m_pb, 0);
if(0)
printf("[%lld] read %05x %d %d (%d)\n", __rdtsc(), off->bp, off->bw, off->psm, page);
}
}
}
delete [] pages;
}
bool GSRendererCS::GetOffsetBuffer(OffsetBuffer** fzbo)
{
HRESULT hr;
GSDevice11* dev = (GSDevice11*)m_dev;
D3D11_BUFFER_DESC bd;
D3D11_SHADER_RESOURCE_VIEW_DESC srvd;
D3D11_SUBRESOURCE_DATA data;
hash_map<uint32, OffsetBuffer>::iterator i = m_offset.find(m_context->offset.fzb->hash);
if(i == m_offset.end())
{
OffsetBuffer ob;
memset(&bd, 0, sizeof(bd));
bd.ByteWidth = sizeof(GSVector2i) * 2048;
bd.Usage = D3D11_USAGE_IMMUTABLE;
bd.BindFlags = D3D11_BIND_SHADER_RESOURCE;
memset(&data, 0, sizeof(data));
data.pSysMem = m_context->offset.fzb->row;
hr = (*dev)->CreateBuffer(&bd, &data, &ob.row);
if(FAILED(hr)) return false;
data.pSysMem = m_context->offset.fzb->col;
hr = (*dev)->CreateBuffer(&bd, &data, &ob.col);
if(FAILED(hr)) return false;
memset(&srvd, 0, sizeof(srvd));
srvd.Format = DXGI_FORMAT_R32G32_SINT;
srvd.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
srvd.Buffer.FirstElement = 0;
srvd.Buffer.NumElements = 2048;
hr = (*dev)->CreateShaderResourceView(ob.row, &srvd, &ob.row_srv);
if(FAILED(hr)) return false;
hr = (*dev)->CreateShaderResourceView(ob.col, &srvd, &ob.col_srv);
if(FAILED(hr)) return false;
m_offset[m_context->offset.fzb->hash] = ob;
i = m_offset.find(m_context->offset.fzb->hash);
}
*fzbo = &i->second;
return true;
}

View File

@ -0,0 +1,145 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSRenderer.h"
#include "GSDevice11.h"
class GSRendererCS : public GSRenderer
{
struct VSSelector
{
union
{
struct
{
uint32 tme:1;
uint32 fst:1;
};
uint32 key;
};
operator uint32() {return key & 0x3;}
VSSelector() : key(0) {}
};
__aligned(struct, 32) VSConstantBuffer
{
GSVector4 VertexScale;
GSVector4 VertexOffset;
};
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 fpsm:6;
uint32 zpsm:6;
};
uint32 key;
};
operator uint32() {return key & 0x3ff;}
PSSelector() : key(0) {}
};
__aligned(struct, 32) PSConstantBuffer
{
uint32 fm;
uint32 zm;
};
CComPtr<ID3D11DepthStencilState> m_dss;
CComPtr<ID3D11BlendState> m_bs;
CComPtr<ID3D11SamplerState> m_ss;
CComPtr<ID3D11Buffer> m_lb;
CComPtr<ID3D11UnorderedAccessView> m_lb_uav;
CComPtr<ID3D11ShaderResourceView> m_lb_srv;
CComPtr<ID3D11Buffer> m_sob;
CComPtr<ID3D11UnorderedAccessView> m_sob_uav;
CComPtr<ID3D11ShaderResourceView> m_sob_srv;
CComPtr<ID3D11Buffer> m_vm;
//CComPtr<ID3D11Texture2D> m_vm;
CComPtr<ID3D11UnorderedAccessView> m_vm_uav;
uint32 m_vm_valid[16];
CComPtr<ID3D11Buffer> m_pb;
//CComPtr<ID3D11Texture2D> m_pb;
hash_map<uint32, GSVertexShader11 > m_vs;
CComPtr<ID3D11Buffer> m_vs_cb;
hash_map<uint32, CComPtr<ID3D11GeometryShader> > m_gs;
CComPtr<ID3D11PixelShader> m_ps0;
hash_map<uint32, CComPtr<ID3D11PixelShader> > m_ps1;
CComPtr<ID3D11Buffer> m_ps_cb;
void Write(GSOffset* off, const GSVector4i& r);
void Read(GSOffset* off, const GSVector4i& r, bool invalidate);
struct OffsetBuffer
{
CComPtr<ID3D11Buffer> row, col;
CComPtr<ID3D11ShaderResourceView> row_srv, col_srv;
};
hash_map<uint32, OffsetBuffer> m_offset;
bool GetOffsetBuffer(OffsetBuffer** fzbo);
protected:
GSTexture* m_texture[2];
uint8* m_output;
bool CreateDevice(GSDevice* dev);
void ResetDevice();
void VSync(int field);
GSTexture* GetOutput(int i);
void Draw();
void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r);
void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r, bool clut);
public:
GSRendererCS();
virtual ~GSRendererCS();
};

View File

@ -0,0 +1,530 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSRendererDX.h"
#include "GSDeviceDX.h"
GSRendererDX::GSRendererDX(GSTextureCache* tc, const GSVector2& pixelcenter)
: GSRendererHW(tc)
, m_pixelcenter(pixelcenter)
{
m_logz = !!theApp.GetConfig("logz", 0);
m_fba = !!theApp.GetConfig("fba", 1);
UserHacks_AlphaHack = !!theApp.GetConfig("UserHacks_AlphaHack", 0) && !!theApp.GetConfig("UserHacks", 0);
UserHacks_AlphaStencil = !!theApp.GetConfig("UserHacks_AlphaStencil", 0) && !!theApp.GetConfig("UserHacks", 0);
UserHacks_TCOffset = !!theApp.GetConfig("UserHacks", 0) ? theApp.GetConfig("UserHacks_TCOffset", 0) : 0;
UserHacks_TCO_x = (UserHacks_TCOffset & 0xFFFF) / -1000.0f;
UserHacks_TCO_y = ((UserHacks_TCOffset >> 16) & 0xFFFF) / -1000.0f;
}
GSRendererDX::~GSRendererDX()
{
}
void GSRendererDX::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* tex)
{
GSDrawingEnvironment& env = m_env;
GSDrawingContext* context = m_context;
const GSVector2i& rtsize = ds ? ds->GetSize() : rt->GetSize();
const GSVector2& rtscale = ds ? ds->GetScale() : rt->GetScale();
bool DATE = m_context->TEST.DATE && context->FRAME.PSM != PSM_PSMCT24;
GSTexture* rtcopy = NULL;
ASSERT(m_dev != NULL);
GSDeviceDX* dev = (GSDeviceDX*)m_dev;
if(DATE)
{
if(dev->HasStencil())
{
GSVector4 s = GSVector4(rtscale.x / rtsize.x, rtscale.y / rtsize.y);
GSVector4 off = GSVector4(-1.0f, 1.0f);
GSVector4 src = ((m_vt.m_min.p.xyxy(m_vt.m_max.p) + off.xxyy()) * s.xyxy()).sat(off.zzyy());
GSVector4 dst = src * 2.0f + off.xxxx();
GSVertexPT1 vertices[] =
{
{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)},
};
dev->SetupDATE(rt, ds, vertices, m_context->TEST.DATM);
}
else
{
rtcopy = dev->CreateRenderTarget(rtsize.x, rtsize.y, false, rt->GetFormat());
// I'll use VertexTrace when I consider it more trustworthy
dev->CopyRect(rt, rtcopy, GSVector4i(rtsize).zwxy());
}
}
//
dev->BeginScene();
// om
GSDeviceDX::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;
}
GSDeviceDX::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
GSDeviceDX::VSSelector vs_sel;
vs_sel.tme = PRIM->TME;
vs_sel.fst = PRIM->FST;
vs_sel.logz = dev->HasDepth32() ? 0 : m_logz ? 1 : 0;
vs_sel.rtcopy = !!rtcopy;
// 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;
}
}
}
}
GSDeviceDX::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 && 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);
// gs
GSDeviceDX::GSSelector gs_sel;
gs_sel.iip = PRIM->IIP;
gs_sel.prim = m_vt.m_primclass;
// ps
GSDeviceDX::PSSelector ps_sel;
GSDeviceDX::PSSamplerSelector ps_ssel;
GSDeviceDX::PSConstantBuffer ps_cb;
// Gregory: code is not yet ready so let's only enable it when
// CRC is below the FULL level
if (m_texture_shuffle && (m_crc_hack_level < 3)) {
ps_sel.shuffle = 1;
ps_sel.fmt = 0;
const GIFRegXYOFFSET& o = m_context->XYOFFSET;
GSVertex* v = &m_vertex.buff[0];
size_t count = m_vertex.next;
// vertex position is 8 to 16 pixels, therefore it is the 16-31 bits of the colors
int pos = (v[0].XYZ.X - o.OFX) & 0xFF;
bool write_ba = (pos > 112 && pos < 136);
// Read texture is 8 to 16 pixels (same as above)
int tex_pos = v[0].U & 0xFF;
ps_sel.read_ba = (tex_pos > 112 && tex_pos < 144);
GL_INS("Color shuffle %s => %s", ps_sel.read_ba ? "BA" : "RG", write_ba ? "BA" : "RG");
// Convert the vertex info to a 32 bits color format equivalent
for (size_t i = 0; i < count; i += 2) {
if (write_ba)
v[i].XYZ.X -= 128u;
else
v[i + 1].XYZ.X += 128u;
if (ps_sel.read_ba)
v[i].U -= 128u;
else
v[i + 1].U += 128u;
// Height is too big (2x).
int tex_offset = v[i].V & 0xF;
GSVector4i offset(o.OFY, tex_offset, o.OFY, tex_offset);
GSVector4i tmp(v[i].XYZ.Y, v[i].V, v[i + 1].XYZ.Y, v[i + 1].V);
tmp = GSVector4i(tmp - offset).srl32(1) + offset;
v[i].XYZ.Y = tmp.x;
v[i].V = tmp.y;
v[i + 1].XYZ.Y = tmp.z;
v[i + 1].V = tmp.w;
}
// Please bang my head against the wall!
// 1/ Reduce the frame mask to a 16 bit format
const uint32& m = context->FRAME.FBMSK;
uint32 fbmask = ((m >> 3) & 0x1F) | ((m >> 6) & 0x3E0) | ((m >> 9) & 0x7C00) | ((m >> 31) & 0x8000);
om_bsel.wrgba = 0;
// 2 Select the new mask (Please someone put SSE here)
if ((fbmask & 0xFF) == 0) {
if (write_ba)
om_bsel.wb = 1;
else
om_bsel.wr = 1;
}
else if ((fbmask & 0xFF) != 0xFF) {
#ifdef _DEBUG
fprintf(stderr, "Please fix me! wb %d wr %d\n", om_bsel.wb, om_bsel.wr);
#endif
//ASSERT(0);
}
fbmask >>= 8;
if ((fbmask & 0xFF) == 0) {
if (write_ba)
om_bsel.wa = 1;
else
om_bsel.wg = 1;
}
else if ((fbmask & 0xFF) != 0xFF) {
#ifdef _DEBUG
fprintf(stderr, "Please fix me! wa %d wg %d\n", om_bsel.wa, om_bsel.wg);
#endif
//ASSERT(0);
}
}
else {
//ps_sel.fmt = GSLocalMemory::m_psm[context->FRAME.PSM].fmt;
om_bsel.wrgba = ~GSVector4i::load((int)context->FRAME.FBMSK).eq8(GSVector4i::xffffffff()).mask();
}
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;
ps_sel.aout &= !ps_sel.shuffle;
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;
else
ps_sel.atst = ATST_ALWAYS;
if (context->TEST.ATE && context->TEST.ATST > 1)
ps_cb.FogColor_AREF.a = (float)context->TEST.AREF;
// Destination alpha pseudo stencil hack: use a stencil operation combined with an alpha test
// to only draw pixels which would cause the destination alpha test to fail in the future once.
// Unfortunately this also means only drawing those pixels at all, which is why this is a hack.
// The interaction with FBA in D3D9 is probably less than ideal.
if (UserHacks_AlphaStencil && DATE && dev->HasStencil() && om_bsel.wa && (!context->TEST.ATE || context->TEST.ATST == 1))
{
if (!context->FBA.FBA)
{
if (context->TEST.DATM == 0)
ps_sel.atst = 5; // >=
else
ps_sel.atst = 2; // <
ps_cb.FogColor_AREF.a = (float)0x80;
}
if (!(context->FBA.FBA && context->TEST.DATM == 1))
om_dssel.alpha_stencil = 1;
}
if(tex)
{
const GSLocalMemory::psm_t &psm = GSLocalMemory::m_psm[context->TEX0.PSM];
const GSLocalMemory::psm_t &cpsm = psm.pal > 0 ? GSLocalMemory::m_psm[context->TEX0.CPSM] : psm;
bool bilinear = m_filter == 2 ? m_vt.IsLinear() : m_filter != 0;
bool simple_sample = !tex->m_palette && cpsm.fmt == 0 && context->CLAMP.WMS < 3 && context->CLAMP.WMT < 3;
// Don't force extra filtering on sprite (it creates various upscaling issue)
bilinear &= !((m_vt.m_primclass == GS_SPRITE_CLASS) && m_userhacks_round_sprite_offset && !m_vt.IsLinear());
ps_sel.wms = context->CLAMP.WMS;
ps_sel.wmt = context->CLAMP.WMT;
if (ps_sel.shuffle) {
ps_sel.fmt = 0;
} else {
ps_sel.fmt = tex->m_palette ? cpsm.fmt | 4 : cpsm.fmt;
}
ps_sel.aem = env.TEXA.AEM;
ps_sel.tfx = context->TEX0.TFX;
ps_sel.tcc = context->TEX0.TCC;
ps_sel.ltf = bilinear && !simple_sample;
ps_sel.rt = tex->m_target;
ps_sel.spritehack = tex->m_spritehack_t;
ps_sel.point_sampler = !(bilinear && simple_sample);
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);
// TC Offset Hack
ps_sel.tcoffsethack = !!UserHacks_TCOffset;
ps_cb.TC_OffsetHack = GSVector4(UserHacks_TCO_x, UserHacks_TCO_y).xyxy() / WH.xyxy();
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 = bilinear && simple_sample;
}
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);
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)
{
GSDeviceDX::OMBlendSelector om_bselneg(om_bsel);
GSDeviceDX::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->SetupOM(om_dssel, om_bsel, afix);
}
}
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];
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)
{
GSDeviceDX::OMBlendSelector om_bselneg(om_bsel);
GSDeviceDX::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();
dev->Recycle(rtcopy);
if(om_dssel.fba) UpdateFBA(rt);
}

View File

@ -0,0 +1,47 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSRendererHW.h"
class GSRendererDX : public GSRendererHW
{
GSVector2 m_pixelcenter;
bool m_logz;
bool m_fba;
bool UserHacks_AlphaHack;
bool UserHacks_AlphaStencil;
protected:
virtual void DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* tex);
virtual void SetupIA() = 0;
virtual void UpdateFBA(GSTexture* rt) {}
unsigned int UserHacks_TCOffset;
float UserHacks_TCO_x, UserHacks_TCO_y;
public:
GSRendererDX(GSTextureCache* tc, const GSVector2& pixelcenter = GSVector2(0, 0));
virtual ~GSRendererDX();
};

View File

@ -0,0 +1,84 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSRendererDX11.h"
#include "GSCrc.h"
#include "resource.h"
GSRendererDX11::GSRendererDX11()
: GSRendererDX(new GSTextureCache11(this), GSVector2(-0.5f, -0.5f))
{
}
bool GSRendererDX11::CreateDevice(GSDevice* dev)
{
if(!__super::CreateDevice(dev))
return false;
return true;
}
void GSRendererDX11::SetupIA()
{
GSDevice11* dev = (GSDevice11*)m_dev;
void* ptr = NULL;
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++)
{
if(PRIM->TME && PRIM->FST) d[i].UV &= 0x3FEF3FEF;
}
}
dev->IAUnmapVertexBuffer();
}
dev->IASetIndexBuffer(m_index.buff, m_index.tail);
D3D11_PRIMITIVE_TOPOLOGY t;
switch(m_vt.m_primclass)
{
case GS_POINT_CLASS:
t = D3D11_PRIMITIVE_TOPOLOGY_POINTLIST;
break;
case GS_LINE_CLASS:
case GS_SPRITE_CLASS:
t = D3D11_PRIMITIVE_TOPOLOGY_LINELIST;
break;
case GS_TRIANGLE_CLASS:
t = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
break;
default:
__assume(0);
}
dev->IASetPrimitiveTopology(t);
}

View File

@ -0,0 +1,38 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSRendererDX.h"
#include "GSVertexHW.h"
#include "GSTextureCache11.h"
class GSRendererDX11 : public GSRendererDX
{
protected:
void SetupIA();
public:
GSRendererDX11();
virtual ~GSRendererDX11() {}
bool CreateDevice(GSDevice* dev);
};

View File

@ -0,0 +1,281 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSRendererDX9.h"
#include "GSCrc.h"
#include "resource.h"
GSRendererDX9::GSRendererDX9()
: GSRendererDX(new GSTextureCache9(this))
{
}
bool GSRendererDX9::CreateDevice(GSDevice* dev)
{
if(!__super::CreateDevice(dev))
return false;
//
memset(&m_fba.dss, 0, sizeof(m_fba.dss));
m_fba.dss.StencilEnable = true;
m_fba.dss.StencilReadMask = 2;
m_fba.dss.StencilWriteMask = 2;
m_fba.dss.StencilFunc = D3DCMP_EQUAL;
m_fba.dss.StencilPassOp = D3DSTENCILOP_ZERO;
m_fba.dss.StencilFailOp = D3DSTENCILOP_ZERO;
m_fba.dss.StencilDepthFailOp = D3DSTENCILOP_ZERO;
m_fba.dss.StencilRef = 2;
memset(&m_fba.bs, 0, sizeof(m_fba.bs));
m_fba.bs.RenderTargetWriteMask = D3DCOLORWRITEENABLE_ALPHA;
//
return true;
}
void GSRendererDX9::SetupIA()
{
D3DPRIMITIVETYPE topology;
switch(m_vt.m_primclass)
{
case GS_POINT_CLASS:
topology = D3DPT_POINTLIST;
break;
case GS_LINE_CLASS:
topology = D3DPT_LINELIST;
if(PRIM->IIP == 0)
{
for(size_t i = 0, j = m_index.tail; i < j; i += 2)
{
uint32 tmp = m_index.buff[i + 0];
m_index.buff[i + 0] = m_index.buff[i + 1];
m_index.buff[i + 1] = tmp;
}
}
break;
case GS_TRIANGLE_CLASS:
topology = D3DPT_TRIANGLELIST;
if(PRIM->IIP == 0)
{
for(size_t i = 0, j = m_index.tail; i < j; i += 3)
{
uint32 tmp = m_index.buff[i + 0];
m_index.buff[i + 0] = m_index.buff[i + 2];
m_index.buff[i + 2] = tmp;
}
}
break;
case GS_SPRITE_CLASS:
topology = D3DPT_TRIANGLELIST;
// each sprite converted to quad needs twice the space
while(m_vertex.tail * 2 > m_vertex.maxcount)
{
GrowVertexBuffer();
}
// assume vertices are tightly packed and sequentially indexed (it should be the case)
if(m_vertex.next >= 2)
{
size_t count = m_vertex.next;
int i = (int)count * 2 - 4;
GSVertex* s = &m_vertex.buff[count - 2];
GSVertex* q = &m_vertex.buff[count * 2 - 4];
uint32* RESTRICT index = &m_index.buff[count * 3 - 6];
for(; i >= 0; i -= 4, s -= 2, q -= 4, index -= 6)
{
GSVertex v0 = s[0];
GSVertex v1 = s[1];
v0.RGBAQ = v1.RGBAQ;
v0.XYZ.Z = v1.XYZ.Z;
v0.FOG = v1.FOG;
q[0] = v0;
q[3] = v1;
// swap x, s, u
uint16 x = v0.XYZ.X;
v0.XYZ.X = v1.XYZ.X;
v1.XYZ.X = x;
float s = v0.ST.S;
v0.ST.S = v1.ST.S;
v1.ST.S = s;
uint16 u = v0.U;
v0.U = v1.U;
v1.U = u;
q[1] = v0;
q[2] = v1;
index[0] = i + 0;
index[1] = i + 1;
index[2] = i + 2;
index[3] = i + 1;
index[4] = i + 2;
index[5] = i + 3;
}
m_vertex.head = m_vertex.tail = m_vertex.next = count * 2;
m_index.tail = count * 3;
}
break;
default:
__assume(0);
}
GSDevice9* dev = (GSDevice9*)m_dev;
(*dev)->SetRenderState(D3DRS_SHADEMODE, PRIM->IIP ? D3DSHADE_GOURAUD : D3DSHADE_FLAT); // TODO
void* ptr = NULL;
if(dev->IAMapVertexBuffer(&ptr, sizeof(GSVertexHW9), m_vertex.next))
{
GSVertex* RESTRICT s = (GSVertex*)m_vertex.buff;
GSVertexHW9* RESTRICT d = (GSVertexHW9*)ptr;
for(uint32 i = 0; i < m_vertex.next; i++, s++, d++)
{
GSVector4 p = GSVector4(GSVector4i::load(s->XYZ.u32[0]).upl16());
if(PRIM->TME && !PRIM->FST)
{
p = p.xyxy(GSVector4((float)s->XYZ.Z, s->RGBAQ.Q));
}
else
{
p = p.xyxy(GSVector4::load((float)s->XYZ.Z));
}
GSVector4 t = GSVector4::zero();
if(PRIM->TME)
{
if(PRIM->FST)
{
if(UserHacks_WildHack && !isPackedUV_HackFlag)
{
t = GSVector4(GSVector4i::load(s->UV & 0x3FEF3FEF).upl16());
//printf("GSDX: %08X | D3D9(%d) %s\n", s->UV & 0x3FEF3FEF, m_vertex.next, i == 0 ? "*" : "");
}
else
{
t = GSVector4(GSVector4i::load(s->UV).upl16());
}
}
else
{
t = GSVector4::loadl(&s->ST);
}
}
t = t.xyxy(GSVector4::cast(GSVector4i(s->RGBAQ.u32[0], s->FOG)));
d->p = p;
d->t = t;
}
dev->IAUnmapVertexBuffer();
}
dev->IASetIndexBuffer(m_index.buff, m_index.tail);
dev->IASetPrimitiveTopology(topology);
}
void GSRendererDX9::UpdateFBA(GSTexture* rt)
{
if (!rt)
return;
GSDevice9* dev = (GSDevice9*)m_dev;
dev->BeginScene();
// om
dev->OMSetDepthStencilState(&m_fba.dss);
dev->OMSetBlendState(&m_fba.bs, 0);
// ia
GSVector4 s = GSVector4(rt->GetScale().x / rt->GetWidth(), rt->GetScale().y / rt->GetHeight());
GSVector4 off = GSVector4(-1.0f, 1.0f);
GSVector4 src = ((m_vt.m_min.p.xyxy(m_vt.m_max.p) + off.xxyy()) * s.xyxy()).sat(off.zzyy());
GSVector4 dst = src * 2.0f + off.xxxx();
GSVertexPT1 vertices[] =
{
{GSVector4(dst.x, -dst.y, 0.5f, 1.0f), GSVector2(0, 0)},
{GSVector4(dst.z, -dst.y, 0.5f, 1.0f), GSVector2(0, 0)},
{GSVector4(dst.x, -dst.w, 0.5f, 1.0f), GSVector2(0, 0)},
{GSVector4(dst.z, -dst.w, 0.5f, 1.0f), GSVector2(0, 0)},
};
dev->IASetVertexBuffer(vertices, sizeof(vertices[0]), countof(vertices));
dev->IASetInputLayout(dev->m_convert.il);
dev->IASetPrimitiveTopology(D3DPT_TRIANGLESTRIP);
// vs
dev->VSSetShader(dev->m_convert.vs, NULL, 0);
// ps
dev->PSSetShader(dev->m_convert.ps[4], NULL, 0);
//
dev->DrawPrimitive();
//
dev->EndScene();
}

View File

@ -0,0 +1,45 @@
/*
* 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSRendererDX.h"
#include "GSVertexHW.h"
#include "GSTextureCache9.h"
class GSRendererDX9 : public GSRendererDX
{
protected:
struct
{
Direct3DDepthStencilState9 dss;
Direct3DBlendState9 bs;
} m_fba;
void SetupIA();
void UpdateFBA(GSTexture* rt);
public:
GSRendererDX9();
virtual ~GSRendererDX9() {}
bool CreateDevice(GSDevice* dev);
};

Some files were not shown because too many files have changed in this diff Show More