mirror of https://github.com/PCSX2/pcsx2.git
fork GSdx into a GSdx_legacy plugin
This commit is contained in:
parent
8ccdc05c08
commit
8751203986
|
@ -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)
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
|
|
@ -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
|
|
@ -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
|
@ -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];
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
};
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
};
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
};
|
|
@ -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;
|
||||
};
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
};
|
|
@ -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),
|
||||
};
|
|
@ -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];
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
};
|
||||
|
|
@ -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)
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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"
|
|
@ -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);
|
||||
}
|
||||
};
|
|
@ -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
|
@ -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;
|
||||
}
|
|
@ -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;}
|
||||
};
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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));
|
||||
}
|
|
@ -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;}
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
};
|
|
@ -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];
|
||||
}
|
|
@ -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);
|
||||
};
|
|
@ -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
|
|
@ -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
|
@ -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
|
@ -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();
|
||||
|
||||
};
|
||||
|
|
@ -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
|
||||
};
|
||||
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
@ -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);
|
||||
};
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
};
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
};
|
|
@ -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();
|
||||
}
|
|
@ -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
|
@ -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();}
|
||||
};
|
|
@ -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
|
|
@ -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
|
@ -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
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
|
@ -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);
|
||||
}
|
||||
|
||||
};
|
|
@ -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--;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;}
|
||||
};
|
|
@ -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"
|
|
@ -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;
|
||||
}
|
||||
};
|
|
@ -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
|
@ -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);
|
||||
};
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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);}
|
||||
};
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
@ -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() {}
|
||||
};
|
|
@ -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
|
||||
}
|
|
@ -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
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
};
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
|
||||
};
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
};
|
|
@ -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();
|
||||
}
|
|
@ -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
Loading…
Reference in New Issue