diff --git a/CMakeLists.txt b/CMakeLists.txt index 78bdd34677..872b0ede45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1015,12 +1015,14 @@ add_library(GPU OBJECT GPU/Math3D.h GPU/Null/NullGpu.cpp GPU/Null/NullGpu.h + GPU/Software/Clipper.cpp + GPU/Software/Clipper.h + GPU/Software/Rasterizer.cpp + GPU/Software/Rasterizer.h GPU/Software/SoftGpu.cpp GPU/Software/SoftGpu.h GPU/Software/TransformUnit.cpp GPU/Software/TransformUnit.h - GPU/Software/Rasterizer.cpp - GPU/Software/Rasterizer.h GPU/ge_constants.h) setup_target_project(GPU GPU) diff --git a/GPU/CMakeLists.txt b/GPU/CMakeLists.txt index 3fc202f2ce..5710379d5f 100644 --- a/GPU/CMakeLists.txt +++ b/GPU/CMakeLists.txt @@ -14,6 +14,7 @@ set(SRCS GLES/VertexDecoder.cpp GLES/VertexShaderGenerator.cpp Null/NullGpu.cpp + Software/Clipper.cpp Software/Rasterizer.cpp Software/SoftGpu.cpp Software/TransformUnit.cpp diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index 74a39941c9..1a6fe6e41a 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -162,6 +162,7 @@ + @@ -186,6 +187,7 @@ + diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index 6dd46c9121..04f8c18fe9 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -68,6 +68,9 @@ GLES + + Software + Software @@ -126,6 +129,9 @@ GLES + + Software + Software diff --git a/GPU/Software/Clipper.cpp b/GPU/Software/Clipper.cpp new file mode 100644 index 0000000000..adcc1543c8 --- /dev/null +++ b/GPU/Software/Clipper.cpp @@ -0,0 +1,170 @@ +// Copyright (c) 2013- PPSSPP Project. + +// 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, version 2.0 or later versions. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "Clipper.h" +#include "Rasterizer.h" + +namespace Clipper { + +enum { + SKIP_FLAG = -1, + CLIP_POS_X_BIT = 0x01, + CLIP_NEG_X_BIT = 0x02, + CLIP_POS_Y_BIT = 0x04, + CLIP_NEG_Y_BIT = 0x08, + CLIP_POS_Z_BIT = 0x10, + CLIP_NEG_Z_BIT = 0x20, +}; + +static inline int CalcClipMask(const ClipCoords& v) +{ + int mask = 0; + if (v.x > v.w) mask |= CLIP_POS_X_BIT; + if (v.x < -v.w) mask |= CLIP_NEG_X_BIT; + if (v.y > v.w) mask |= CLIP_POS_Y_BIT; + if (v.y < -v.w) mask |= CLIP_NEG_Y_BIT; + if (v.z > v.w) mask |= CLIP_POS_Z_BIT; + if (v.z < -v.w) mask |= CLIP_NEG_Z_BIT; + return mask; +} + +#define AddInterpolatedVertex(t, out, in, numVertices) \ +{ \ + Vertices[numVertices]->Lerp(t, *Vertices[out], *Vertices[in]); \ + numVertices++; \ +} + +#define DIFFERENT_SIGNS(x,y) ((x <= 0 && y > 0) || (x > 0 && y <= 0)) + +#define CLIP_DOTPROD(I, A, B, C, D) \ + (Vertices[I]->clippos.x * A + Vertices[I]->clippos.y * B + Vertices[I]->clippos.z * C + Vertices[I]->clippos.w * D) + +#define POLY_CLIP( PLANE_BIT, A, B, C, D ) \ +{ \ + if (mask & PLANE_BIT) { \ + int idxPrev = inlist[0]; \ + float dpPrev = CLIP_DOTPROD(idxPrev, A, B, C, D ); \ + int outcount = 0; \ + \ + inlist[n] = inlist[0]; \ + for (int j = 1; j <= n; j++) { \ + int idx = inlist[j]; \ + float dp = CLIP_DOTPROD(idx, A, B, C, D ); \ + if (dpPrev >= 0) { \ + outlist[outcount++] = idxPrev; \ + } \ + \ + if (DIFFERENT_SIGNS(dp, dpPrev)) { \ + if (dp < 0) { \ + float t = dp / (dp - dpPrev); \ + AddInterpolatedVertex(t, idx, idxPrev, numVertices); \ + } else { \ + float t = dpPrev / (dpPrev - dp); \ + AddInterpolatedVertex(t, idxPrev, idx, numVertices); \ + } \ + outlist[outcount++] = numVertices - 1; \ + } \ + \ + idxPrev = idx; \ + dpPrev = dp; \ + } \ + \ + if (outcount < 3) \ + continue; \ + \ + { \ + int *tmp = inlist; \ + inlist = outlist; \ + outlist = tmp; \ + n = outcount; \ + } \ + } \ +} + +void ProcessTriangle(VertexData* data) +{ + enum { NUM_CLIPPED_VERTICES = 33, NUM_INDICES = NUM_CLIPPED_VERTICES + 3 }; + + VertexData* Vertices[NUM_CLIPPED_VERTICES]; + VertexData ClippedVertices[NUM_CLIPPED_VERTICES]; + for (int i = 0; i < NUM_CLIPPED_VERTICES; ++i) + Vertices[i+3] = &ClippedVertices[i]; + + // TODO: Change logic when it's a backface + Vertices[0] = &data[0]; + Vertices[1] = &data[1]; + Vertices[2] = &data[2]; + + int indices[NUM_INDICES] = { 0, 1, 2, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, + SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, + SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG }; + int numIndices = 3; + + int mask = 0; + mask |= CalcClipMask(data[0].clippos); + mask |= CalcClipMask(data[1].clippos); + mask |= CalcClipMask(data[2].clippos); + + if (mask) { + for(int i = 0; i < 3; i += 3) { + int vlist[2][2*6+1]; + int *inlist = vlist[0], *outlist = vlist[1]; + int n = 3; + int numVertices = 3; + + inlist[0] = 0; + inlist[1] = 1; + inlist[2] = 2; + + // mark this triangle as unused in case it should be completely clipped + indices[0] = SKIP_FLAG; + indices[1] = SKIP_FLAG; + indices[2] = SKIP_FLAG; + + POLY_CLIP(CLIP_POS_X_BIT, -1, 0, 0, 1); + POLY_CLIP(CLIP_NEG_X_BIT, 1, 0, 0, 1); + POLY_CLIP(CLIP_POS_Y_BIT, 0, -1, 0, 1); + POLY_CLIP(CLIP_NEG_Y_BIT, 0, 1, 0, 1); + POLY_CLIP(CLIP_POS_Z_BIT, 0, 0, 0, 1); + POLY_CLIP(CLIP_NEG_Z_BIT, 0, 0, 1, 1); + + // transform the poly in inlist into triangles + indices[0] = inlist[0]; + indices[1] = inlist[1]; + indices[2] = inlist[2]; + for (int j = 3; j < n; ++j) { + indices[numIndices++] = inlist[0]; + indices[numIndices++] = inlist[j - 1]; + indices[numIndices++] = inlist[j]; + } + } + } + + for(int i = 0; i+3 <= numIndices; i+=3) + { + if(indices[i] != SKIP_FLAG) + { + VertexData data[3] = { *Vertices[indices[i]], *Vertices[indices[i+1]], *Vertices[indices[i+2]] }; + data[0].drawpos = DrawingCoords(TransformUnit::ScreenToDrawing(TransformUnit::ClipToScreen(data[0].clippos))); + data[1].drawpos = DrawingCoords(TransformUnit::ScreenToDrawing(TransformUnit::ClipToScreen(data[1].clippos))); + data[2].drawpos = DrawingCoords(TransformUnit::ScreenToDrawing(TransformUnit::ClipToScreen(data[2].clippos))); + Rasterizer::DrawTriangle(data); + } + } +} + +} // namespace diff --git a/GPU/Software/Clipper.h b/GPU/Software/Clipper.h new file mode 100644 index 0000000000..c8f84efd77 --- /dev/null +++ b/GPU/Software/Clipper.h @@ -0,0 +1,26 @@ +// Copyright (c) 2013- PPSSPP Project. + +// 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, version 2.0 or later versions. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +#include "TransformUnit.h" + +namespace Clipper { + +void ProcessTriangle(VertexData* data); + +} diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index 369670b801..5135805de5 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -19,7 +19,7 @@ #include "../GLES/VertexDecoder.h" #include "TransformUnit.h" -#include "Rasterizer.h" +#include "Clipper.h" WorldCoords TransformUnit::ModelToWorld(const ModelCoords& coords) { @@ -60,88 +60,11 @@ DrawingCoords TransformUnit::ScreenToDrawing(const ScreenCoords& coords) { DrawingCoords ret; // TODO: What to do when offset > coord? - // TODO: Mask can be re-enabled now, I guess. ret.x = (((u32)coords.x - (gstate.offsetx&0xffff))/16) & 0x3ff; ret.y = (((u32)coords.y - (gstate.offsety&0xffff))/16) & 0x3ff; return ret; } -enum { - SKIP_FLAG = -1, - CLIP_POS_X_BIT = 0x01, - CLIP_NEG_X_BIT = 0x02, - CLIP_POS_Y_BIT = 0x04, - CLIP_NEG_Y_BIT = 0x08, - CLIP_POS_Z_BIT = 0x10, - CLIP_NEG_Z_BIT = 0x20, -}; - -static inline int CalcClipMask(const ClipCoords& v) -{ - int mask = 0; - // TODO: Do we need to include the equal sign here, too? - if (v.x > v.w) mask |= CLIP_POS_X_BIT; - if (v.x < -v.w) mask |= CLIP_NEG_X_BIT; - if (v.y > v.w) mask |= CLIP_POS_Y_BIT; - if (v.y < -v.w) mask |= CLIP_NEG_Y_BIT; - if (v.z > v.w) mask |= CLIP_POS_Z_BIT; - if (v.z < -v.w) mask |= CLIP_NEG_Z_BIT; - return mask; -} - -#define AddInterpolatedVertex(t, out, in, numVertices) \ -{ \ - Vertices[numVertices]->Lerp(t, *Vertices[out], *Vertices[in]); \ - numVertices++; \ -} - -#define DIFFERENT_SIGNS(x,y) ((x <= 0 && y > 0) || (x > 0 && y <= 0)) - -#define CLIP_DOTPROD(I, A, B, C, D) \ - (Vertices[I]->clippos.x * A + Vertices[I]->clippos.y * B + Vertices[I]->clippos.z * C + Vertices[I]->clippos.w * D) - -#define POLY_CLIP( PLANE_BIT, A, B, C, D ) \ -{ \ - if (mask & PLANE_BIT) { \ - int idxPrev = inlist[0]; \ - float dpPrev = CLIP_DOTPROD(idxPrev, A, B, C, D ); \ - int outcount = 0; \ - \ - inlist[n] = inlist[0]; \ - for (int j = 1; j <= n; j++) { \ - int idx = inlist[j]; \ - float dp = CLIP_DOTPROD(idx, A, B, C, D ); \ - if (dpPrev >= 0) { \ - outlist[outcount++] = idxPrev; \ - } \ - \ - if (DIFFERENT_SIGNS(dp, dpPrev)) { \ - if (dp < 0) { \ - float t = dp / (dp - dpPrev); \ - AddInterpolatedVertex(t, idx, idxPrev, numVertices); \ - } else { \ - float t = dpPrev / (dpPrev - dp); \ - AddInterpolatedVertex(t, idxPrev, idx, numVertices); \ - } \ - outlist[outcount++] = numVertices - 1; \ - } \ - \ - idxPrev = idx; \ - dpPrev = dp; \ - } \ - \ - if (outcount < 3) \ - continue; \ - \ - { \ - int *tmp = inlist; \ - inlist = outlist; \ - outlist = tmp; \ - n = outcount; \ - } \ - } \ -} - void TransformUnit::SubmitPrimitive(void* vertices, u32 prim_type, int vertex_count, u32 vertex_type) { // TODO: Cache VertexDecoder objects @@ -157,19 +80,8 @@ void TransformUnit::SubmitPrimitive(void* vertices, u32 prim_type, int vertex_co // We only support triangle lists, for now. for (int vtx = 0; vtx < vertex_count; vtx+=3) { - enum { NUM_CLIPPED_VERTICES = 33, NUM_INDICES = NUM_CLIPPED_VERTICES + 3 }; - VertexData* Vertices[NUM_CLIPPED_VERTICES]; - VertexData ClippedVertices[NUM_CLIPPED_VERTICES]; VertexData data[3]; - for (int i = 0; i < NUM_CLIPPED_VERTICES; ++i) - Vertices[i+3] = &ClippedVertices[i]; - - // TODO: Change logic when it's a backface - Vertices[0] = &data[0]; - Vertices[1] = &data[1]; - Vertices[2] = &data[2]; - for (unsigned int i = 0; i < 3; ++i) { float pos[3]; @@ -190,62 +102,6 @@ void TransformUnit::SubmitPrimitive(void* vertices, u32 prim_type, int vertex_co // TODO: Should do lighting here! - int indices[NUM_INDICES] = { 0, 1, 2, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, - SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, - SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG }; - int numIndices = 3; - - int mask = 0; - mask |= CalcClipMask(data[0].clippos); - mask |= CalcClipMask(data[1].clippos); - mask |= CalcClipMask(data[2].clippos); - - if (mask) { - for(int i = 0; i < 3; i += 3) { - int vlist[2][2*6+1]; - int *inlist = vlist[0], *outlist = vlist[1]; - int n = 3; - int numVertices = 3; - - inlist[0] = 0; - inlist[1] = 1; - inlist[2] = 2; - - // mark this triangle as unused in case it should be completely clipped - indices[0] = SKIP_FLAG; - indices[1] = SKIP_FLAG; - indices[2] = SKIP_FLAG; - - POLY_CLIP(CLIP_POS_X_BIT, -1, 0, 0, 1); - POLY_CLIP(CLIP_NEG_X_BIT, 1, 0, 0, 1); - POLY_CLIP(CLIP_POS_Y_BIT, 0, -1, 0, 1); - POLY_CLIP(CLIP_NEG_Y_BIT, 0, 1, 0, 1); - POLY_CLIP(CLIP_POS_Z_BIT, 0, 0, 0, 1); - POLY_CLIP(CLIP_NEG_Z_BIT, 0, 0, 1, 1); - - // transform the poly in inlist into triangles - indices[0] = inlist[0]; - indices[1] = inlist[1]; - indices[2] = inlist[2]; - for (int j = 3; j < n; ++j) { - indices[numIndices++] = inlist[0]; - indices[numIndices++] = inlist[j - 1]; - indices[numIndices++] = inlist[j]; - } - } - } - - for(int i = 0; i+3 <= numIndices; i+=3) - { - if(indices[i] != SKIP_FLAG) - { - VertexData data[3] = { *Vertices[indices[i]], *Vertices[indices[i+1]], *Vertices[indices[i+2]] }; - data[0].drawpos = DrawingCoords(TransformUnit::ScreenToDrawing(TransformUnit::ClipToScreen(data[0].clippos))); - data[1].drawpos = DrawingCoords(TransformUnit::ScreenToDrawing(TransformUnit::ClipToScreen(data[1].clippos))); - data[2].drawpos = DrawingCoords(TransformUnit::ScreenToDrawing(TransformUnit::ClipToScreen(data[2].clippos))); - Rasterizer::DrawTriangle(data); - } - } -skip:; + Clipper::ProcessTriangle(data); } }