Skip to content

Commit

Permalink
[spline/bezier]Modify ControlPoints and fix VertexPreview.
Browse files Browse the repository at this point in the history
  • Loading branch information
xebra committed Oct 7, 2018
1 parent 1c604d5 commit 019e276
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 98 deletions.
35 changes: 22 additions & 13 deletions GPU/Common/SplineCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
#include "profiler/profiler.h"

#include "Common/CPUDetect.h"
#include "Common/MemoryUtil.h"

#include "GPU/Common/GPUStateUtils.h"
#include "GPU/Common/SplineCommon.h"
Expand Down Expand Up @@ -315,6 +314,22 @@ class SimpleBufferManager {
}
};

ControlPoints::ControlPoints(const SimpleVertex *const *points, int size, SimpleBufferManager &managedBuf) {
pos = (Vec3f *)managedBuf.Allocate(sizeof(Vec3f) * size);
tex = (Vec2f *)managedBuf.Allocate(sizeof(Vec2f) * size);
col = (Vec4f *)managedBuf.Allocate(sizeof(Vec4f) * size);
Convert(points, size);
}

void ControlPoints::Convert(const SimpleVertex *const *points, int size) {
for (int i = 0; i < size; ++i) {
pos[i] = Vec3f(points[i]->pos);
tex[i] = Vec2f(points[i]->uv);
col[i] = Vec4f::FromRGBA(points[i]->color_32);
}
defcolor = points[0]->color_32;
}

template<class Patch>
class SubdivisionSurface {
private:
Expand Down Expand Up @@ -415,21 +430,13 @@ class SubdivisionSurface {
};

template<class Patch>
static void SoftwareTessellation(OutputBuffers &output, const Patch &patch, u32 origVertType,
const SimpleVertex *const *points, SimpleBufferManager &managedBuf) {
void SoftwareTessellation(OutputBuffers &output, const Patch &patch, u32 origVertType, const ControlPoints &points) {
using WeightType = Patch::WeightType;
u32 key_u = WeightType::ToKey(patch.tess_u, patch.count_u, patch.type_u);
u32 key_v = WeightType::ToKey(patch.tess_v, patch.count_v, patch.type_v);
Weight2D weights(weightsCache<WeightType>, key_u, key_v);

int size = patch.count_u * patch.count_v;
ControlPoints cpoints;
cpoints.pos = (Vec3f *)managedBuf.Allocate(sizeof(Vec3f) * size);
cpoints.tex = (Vec2f *)managedBuf.Allocate(sizeof(Vec2f) * size);
cpoints.col = (Vec4f *)managedBuf.Allocate(sizeof(Vec4f) * size);
cpoints.Convert(points, size);

SubdivisionSurface<Patch> surface(cpoints, patch, weights);
SubdivisionSurface<Patch> surface(points, patch, weights);
surface.Tessellate(output, origVertType);
}

Expand Down Expand Up @@ -523,8 +530,9 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi
HardwareTessellation(output, patch, origVertType, points, tessDataTransfer);
numPatches = patch.num_patches_u * patch.num_patches_v;
} else {
ControlPoints cpoints(points, count_u * count_v, managedBuf);
patch.Init(SPLINE_BUFFER_SIZE / vertexSize);
SoftwareTessellation(output, patch, origVertType, points, managedBuf);
SoftwareTessellation(output, patch, origVertType, cpoints);
}

u32 vertTypeWithIndex16 = (vertType & ~GE_VTYPE_IDX_MASK) | GE_VTYPE_IDX_16BIT;
Expand Down Expand Up @@ -614,8 +622,9 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi
HardwareTessellation(output, patch, origVertType, points, tessDataTransfer);
numPatches = patch.num_patches_u * patch.num_patches_v;
} else {
ControlPoints cpoints(points, count_u * count_v, managedBuf);
patch.Init(SPLINE_BUFFER_SIZE / vertexSize);
SoftwareTessellation(output, patch, origVertType, points, managedBuf);
SoftwareTessellation(output, patch, origVertType, cpoints);
}

u32 vertTypeWithIndex16 = (vertType & ~GE_VTYPE_IDX_MASK) | GE_VTYPE_IDX_16BIT;
Expand Down
18 changes: 8 additions & 10 deletions GPU/Common/SplineCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,20 +198,17 @@ struct Weight2D {
}
};

class SimpleBufferManager;

struct ControlPoints {
Vec3f *pos;
Vec2f *tex;
Vec4f *col;
u32_le defcolor;

void Convert(const SimpleVertex *const *points, int size) {
for (int i = 0; i < size; ++i) {
pos[i] = Vec3f(points[i]->pos);
tex[i] = Vec2f(points[i]->uv);
col[i] = Vec4f::FromRGBA(points[i]->color_32);
}
defcolor = points[0]->color_32;
}
ControlPoints() {}
ControlPoints(const SimpleVertex *const *points, int size, SimpleBufferManager &managedBuf);
void Convert(const SimpleVertex *const *points, int size);
};

struct OutputBuffers {
Expand All @@ -221,8 +218,9 @@ struct OutputBuffers {
};

bool CanUseHardwareTessellation(GEPatchPrimType prim);
void TessellateSplinePatch(u8 *&dest, u16 *indices, int &count, SplinePatchLocal &spatch, u32 origVertType, int maxVertices);
void TessellateBezierPatch(u8 *&dest, u16 *&indices, int &count, int tess_u, int tess_v, const BezierPatch &patch, u32 origVertType, int maxVertices);

template<class Patch>
void SoftwareTessellation(OutputBuffers &output, const Patch &patch, u32 origVertType, const ControlPoints &points);

// Define function object for TemplateParameterDispatcher
#define TEMPLATE_PARAMETER_DISPATCHER_FUNCTION(NAME, FUNCNAME) \
Expand Down
157 changes: 82 additions & 75 deletions Windows/GEDebugger/VertexPreview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "GPU/Common/GPUDebugInterface.h"
#include "GPU/Common/SplineCommon.h"
#include "GPU/GPUState.h"
#include "Common/MemoryUtil.h"

static const char preview_fs[] =
"#ifdef GL_ES\n"
Expand Down Expand Up @@ -164,106 +165,112 @@ u32 CGEDebugger::PrimPreviewOp() {
}

static void ExpandBezier(int &count, int op, const std::vector<SimpleVertex> &simpleVerts, const std::vector<u16> &indices, std::vector<SimpleVertex> &generatedVerts, std::vector<u16> &generatedInds) {
int count_u = (op & 0x00FF) >> 0;
int count_v = (op & 0xFF00) >> 8;
int count_u = (op >> 0) & 0xFF;
int count_v = (op >> 8) & 0xFF;
// Real hardware seems to draw nothing when given < 4 either U or V.
if (count_u < 4 || count_v < 4)
return;

int tess_u = gstate.getPatchDivisionU();
int tess_v = gstate.getPatchDivisionV();
if (tess_u < 1) {
tess_u = 1;
}
if (tess_v < 1) {
tess_v = 1;
}

// Bezier patches share less control points than spline patches. Otherwise they are pretty much the same (except bezier don't support the open/close thing)
int num_patches_u = (count_u - 1) / 3;
int num_patches_v = (count_v - 1) / 3;
int total_patches = num_patches_u * num_patches_v;

std::vector<const SimpleVertex *> points(count_u * count_v);
for (int idx = 0; idx < count_u * count_v; idx++)
points[idx] = &simpleVerts[0] + (!indices.empty() ? indices[idx] : idx);
// If specified as 0, uses 1.
if (tess_u < 1) tess_u = 1;
if (tess_v < 1) tess_v = 1;

BezierPatch patch;
patch.count_u = count_u;
patch.count_v = count_v;
patch.tess_u = tess_u;
patch.tess_v = tess_v;
patch.num_patches_u = (count_u - 1) / 3;
patch.num_patches_v = (count_v - 1) / 3;
patch.primType = gstate.getPatchPrimitiveType();
patch.patchFacing = false;
patch.defcolor = 0xFFFFFFFF;

std::vector<Vec3f> pos(patch.count_u * patch.count_v);
std::vector<Vec2f> tex(patch.count_u * patch.count_v);
std::vector<Vec4f> col(patch.count_u * patch.count_v);
patch.pos = pos.data();
patch.tex = tex.data();
patch.col = col.data();
for (int idx = 0; idx < count_u * count_v; idx++) {
patch.pos[idx] = Vec3f(points[idx]->pos);
patch.tex[idx] = Vec2f(points[idx]->uv);
patch.col[idx] = Vec4f::FromRGBA(points[idx]->color_32);
}

// Make an array of pointers to the control points, to get rid of indices.
std::vector<const SimpleVertex *> points(count_u * count_v);
for (int idx = 0; idx < count_u * count_v; idx++)
points[idx] = simpleVerts.data() + (!indices.empty() ? indices[idx] : idx);

int total_patches = patch.num_patches_u * patch.num_patches_v;
generatedVerts.resize((tess_u + 1) * (tess_v + 1) * total_patches);
generatedInds.resize(tess_u * tess_v * 6 * total_patches);

count = 0;
u8 *dest = (u8 *)&generatedVerts[0];
u16 *inds = &generatedInds[0];
TessellateBezierPatch(dest, inds, count, tess_u, tess_v, patch, gstate.vertType, generatedVerts.size());
OutputBuffers output;
output.vertices = generatedVerts.data();
output.indices = generatedInds.data();
output.count = 0;

int size = count_u * count_v;
ControlPoints cpoints;
cpoints.pos = (Vec3f *)AllocateAlignedMemory(sizeof(Vec3f) * size, 16);
cpoints.tex = (Vec2f *)AllocateAlignedMemory(sizeof(Vec2f) * size, 16);
cpoints.col = (Vec4f *)AllocateAlignedMemory(sizeof(Vec4f) * size, 16);
cpoints.Convert(points.data(), size);

patch.Init(generatedVerts.size());
SoftwareTessellation(output, patch, gstate.vertType, cpoints);
count = output.count;

FreeAlignedMemory(cpoints.pos);
FreeAlignedMemory(cpoints.tex);
FreeAlignedMemory(cpoints.col);
}

static void ExpandSpline(int &count, int op, const std::vector<SimpleVertex> &simpleVerts, const std::vector<u16> &indices, std::vector<SimpleVertex> &generatedVerts, std::vector<u16> &generatedInds) {
SplinePatchLocal patch;
patch.primType = gstate.getPatchPrimitiveType();
patch.patchFacing = false;

patch.count_u = (op & 0x00FF) >> 0;
patch.count_v = (op & 0xFF00) >> 8;
patch.type_u = (op >> 16) & 0x3;
patch.type_v = (op >> 18) & 0x3;

patch.tess_u = gstate.getPatchDivisionU();
patch.tess_v = gstate.getPatchDivisionV();
if (patch.tess_u < 1) {
patch.tess_u = 1;
}
if (patch.tess_v < 1) {
patch.tess_v = 1;
}

int count_u = (op >> 0) & 0xFF;
int count_v = (op >> 8) & 0xFF;
// Real hardware seems to draw nothing when given < 4 either U or V.
if (patch.count_u < 4 || patch.count_v < 4) {
if (count_u < 4 || count_v < 4)
return;
}

std::vector<const SimpleVertex *> points(patch.count_u * patch.count_v);
int tess_u = gstate.getPatchDivisionU();
int tess_v = gstate.getPatchDivisionV();
// If specified as 0, uses 1.
if (tess_u < 1) tess_u = 1;
if (tess_v < 1) tess_v = 1;

// Make an array of pointers to the control points, to get rid of indices.
for (int idx = 0; idx < patch.count_u * patch.count_v; idx++) {
points[idx] = &simpleVerts[0] + (!indices.empty() ? indices[idx] : idx);
}
std::vector<Vec3f> pos(patch.count_u * patch.count_v);
std::vector<Vec2f> tex(patch.count_u * patch.count_v);
std::vector<Vec4f> col(patch.count_u * patch.count_v);
patch.pos = pos.data();
patch.tex = tex.data();
patch.col = col.data();
for (int idx = 0; idx < patch.count_u * patch.count_v; idx++) {
patch.pos[idx] = Vec3f(points[idx]->pos);
patch.tex[idx] = Vec2f(points[idx]->uv);
patch.col[idx] = Vec4f::FromRGBA(points[idx]->color_32);
}
SplinePatchLocal patch;
patch.count_u = count_u;
patch.count_v = count_v;
patch.tess_u = tess_u;
patch.tess_v = tess_v;
patch.type_u = (op >> 16) & 0x3;
patch.type_v = (op >> 18) & 0x3;
patch.num_patches_u = count_u - 3;
patch.num_patches_v = count_v - 3;
patch.primType = gstate.getPatchPrimitiveType();
patch.patchFacing = false;

int patch_div_s = (patch.count_u - 3) * patch.tess_u;
int patch_div_t = (patch.count_v - 3) * patch.tess_v;
// Make an array of pointers to the control points, to get rid of indices.
std::vector<const SimpleVertex *> points(count_u * count_v);
for (int idx = 0; idx < count_u * count_v; idx++)
points[idx] = simpleVerts.data() + (!indices.empty() ? indices[idx] : idx);

int patch_div_s = patch.num_patches_u * patch.tess_u;
int patch_div_t = patch.num_patches_v * patch.tess_v;
generatedVerts.resize((patch_div_s + 1) * (patch_div_t + 1));
generatedInds.resize(patch_div_s * patch_div_t * 6);

count = 0;
u8 *dest = (u8 *)&generatedVerts[0];
TessellateSplinePatch(dest, &generatedInds[0], count, patch, gstate.vertType, generatedVerts.size());
OutputBuffers output;
output.vertices = generatedVerts.data();
output.indices = generatedInds.data();
output.count = 0;

int size = count_u * count_v;
ControlPoints cpoints;
cpoints.pos = (Vec3f *)AllocateAlignedMemory(sizeof(Vec3f) * size, 16);
cpoints.tex = (Vec2f *)AllocateAlignedMemory(sizeof(Vec2f) * size, 16);
cpoints.col = (Vec4f *)AllocateAlignedMemory(sizeof(Vec4f) * size, 16);
cpoints.Convert(points.data(), size);

patch.Init(generatedVerts.size());
SoftwareTessellation(output, patch, gstate.vertType, cpoints);
count = output.count;

FreeAlignedMemory(cpoints.pos);
FreeAlignedMemory(cpoints.tex);
FreeAlignedMemory(cpoints.col);
}

void CGEDebugger::UpdatePrimPreview(u32 op, int which) {
Expand Down

0 comments on commit 019e276

Please sign in to comment.