Merge pull request #4567 from unknownbrackets/debugger

Vertex preview (should work for 2D and 3D now)
This commit is contained in:
Henrik Rydgård 2013-11-18 02:49:04 -08:00
commit 221dd153f4
15 changed files with 377 additions and 53 deletions

View file

@ -176,6 +176,14 @@ private:
bool flipped_;
};
struct GPUDebugVertex {
float u;
float v;
float x;
float y;
float z;
};
class GPUDebugInterface {
public:
virtual bool GetCurrentDisplayList(DisplayList &list) = 0;
@ -198,6 +206,10 @@ public:
// Calling from a separate thread (e.g. UI) may fail.
virtual void SetCmdValue(u32 op) = 0;
virtual bool GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices) {
return false;
}
// Needs to be called from the GPU thread, so on the same thread as a notification is fine.
// Calling from a separate thread (e.g. UI) may fail.
virtual bool GetCurrentFramebuffer(GPUDebugBuffer &buffer) {

View file

@ -42,7 +42,7 @@ int DecFmtSize(u8 fmt) {
}
}
void GetIndexBounds(void *inds, int count, u32 vertType, u16 *indexLowerBound, u16 *indexUpperBound) {
void GetIndexBounds(const void *inds, int count, u32 vertType, u16 *indexLowerBound, u16 *indexUpperBound) {
// Find index bounds. Could cache this in display lists.
// Also, this could be greatly sped up with SSE2/NEON, although rarely a bottleneck.
int lowerBound = 0x7FFFFFFF;

View file

@ -71,7 +71,7 @@ struct TransformedVertex
u8 color1[4]; // prelit
};
void GetIndexBounds(void *inds, int count, u32 vertType, u16 *indexLowerBound, u16 *indexUpperBound);
void GetIndexBounds(const void *inds, int count, u32 vertType, u16 *indexLowerBound, u16 *indexUpperBound);
enum {
STAT_VERTSSUBMITTED = 0,

View file

@ -1644,3 +1644,7 @@ bool GLES_GPU::GetCurrentTexture(GPUDebugBuffer &buffer) {
return false;
#endif
}
bool GLES_GPU::GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices) {
return transformDraw_.GetCurrentSimpleVertices(count, vertices, indices);
}

View file

@ -71,6 +71,7 @@ public:
bool GetCurrentDepthbuffer(GPUDebugBuffer &buffer);
bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer);
bool GetCurrentTexture(GPUDebugBuffer &buffer);
bool GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices);
protected:
virtual void FastRunLoop(DisplayList &list);

View file

@ -79,6 +79,7 @@
#include "GPU/GPUState.h"
#include "GPU/ge_constants.h"
#include "GPU/Common/SplineCommon.h"
#include "GPU/GLES/StateMapping.h"
#include "GPU/GLES/TextureCache.h"
#include "GPU/GLES/TransformPipeline.h"
@ -842,3 +843,111 @@ bool TransformDrawEngine::TestBoundingBox(void* control_points, int vertexCount,
return true;
}
// TODO: Probably move this to common code (with normalization?)
static inline Vec3f ClipToScreen(const Vec4f& coords)
{
// TODO: Check for invalid parameters (x2 < x1, etc)
float vpx1 = getFloat24(gstate.viewportx1);
float vpx2 = getFloat24(gstate.viewportx2);
float vpy1 = getFloat24(gstate.viewporty1);
float vpy2 = getFloat24(gstate.viewporty2);
float vpz1 = getFloat24(gstate.viewportz1);
float vpz2 = getFloat24(gstate.viewportz2);
float retx = coords.x * vpx1 / coords.w + vpx2;
float rety = coords.y * vpy1 / coords.w + vpy2;
float retz = coords.z * vpz1 / coords.w + vpz2;
// 16 = 0xFFFF / 4095.9375
return Vec3f(retx * 16, rety * 16, retz);
}
static Vec3f ScreenToDrawing(const Vec3f& coords)
{
Vec3f ret;
ret.x = coords.x - gstate.getOffsetX16();
ret.y = coords.y - gstate.getOffsetY16();
// Convert from 16 point to float.
ret.x *= 1.0 / 16.0;
ret.y *= 1.0 / 16.0;
ret.z = coords.z;
return ret;
}
// TODO: This probably is not the best interface.
bool TransformDrawEngine::GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices) {
// This is always for the current vertices.
u16 indexLowerBound = 0;
u16 indexUpperBound = count - 1;
if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {
const u8 *inds = Memory::GetPointer(gstate_c.indexAddr);
const u16 *inds16 = (const u16 *)inds;
if (inds) {
GetIndexBounds(inds, count, gstate.vertType, &indexLowerBound, &indexUpperBound);
indices.resize(count);
switch (gstate.vertType & GE_VTYPE_IDX_MASK) {
case GE_VTYPE_IDX_16BIT:
for (int i = 0; i < count; ++i) {
indices[i] = inds16[i];
}
break;
case GE_VTYPE_IDX_8BIT:
for (int i = 0; i < count; ++i) {
indices[i] = inds[i];
}
break;
default:
return false;
}
} else {
indices.clear();
}
} else {
indices.clear();
}
// TODO: Manage better.
u8 *temp_buffer = new u8[65536 * 24];
SimpleVertex *simpleVertices = new SimpleVertex[indexUpperBound + 1];
NormalizeVertices((u8 *)simpleVertices, temp_buffer, Memory::GetPointer(gstate_c.vertexAddr), indexLowerBound, indexUpperBound, gstate.vertType);
vertices.resize(indexUpperBound + 1);
for (int i = indexLowerBound; i <= indexUpperBound; ++i) {
const SimpleVertex &vert = simpleVertices[i];
if (gstate.isModeThrough()) {
vertices[i].u = vert.uv[0];
vertices[i].v = vert.uv[1];
vertices[i].x = vert.pos.x;
vertices[i].y = vert.pos.y;
vertices[i].z = vert.pos.z;
} else {
// TODO: This doesn't work correctly and is inefficient.
float worldPos[3];
Vec3ByMatrix43(worldPos, vert.pos.AsArray(), gstate.worldMatrix);
float viewPos[3];
Vec3ByMatrix43(viewPos, worldPos, gstate.viewMatrix);
float clipPos[4];
Vec3ByMatrix44(clipPos, viewPos, gstate.projMatrix);
Vec3f screenPos = ClipToScreen(clipPos);
Vec3f drawPos = ScreenToDrawing(screenPos);
vertices[i].u = vert.uv[0];
vertices[i].v = vert.uv[1];
vertices[i].x = drawPos.x;
vertices[i].y = drawPos.y;
vertices[i].z = 1.0;
}
}
delete [] temp_buffer;
delete [] simpleVertices;
return true;
}

View file

@ -19,6 +19,7 @@
#include <map>
#include "GPU/Common/GPUDebugInterface.h"
#include "GPU/Common/IndexGenerator.h"
#include "GPU/GLES/VertexDecoder.h"
#include "gfx/gl_common.h"
@ -97,6 +98,8 @@ public:
void SubmitBezier(void* control_points, void* indices, int count_u, int count_v, GEPatchPrimType prim_type, u32 vertType);
bool TestBoundingBox(void* control_points, int vertexCount, u32 vertType);
bool GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices);
void SetShaderManager(ShaderManager *shaderManager) {
shaderManager_ = shaderManager;
}

View file

@ -40,6 +40,7 @@ public:
};
T* AsArray() { return &x; }
const T* AsArray() const { return &x; }
Vec2() {}
Vec2(const T a[2]) : x(a[0]), y(a[1]) {}
@ -155,12 +156,6 @@ public:
Vec2 ts() const { return Vec2(y, x); }
};
template<typename T, typename V>
Vec2<T> operator * (const V& f, const Vec2<T>& vec)
{
return Vec2<T>(f*vec.x,f*vec.y);
}
typedef Vec2<float> Vec2f;
template<typename T>
@ -173,6 +168,7 @@ public:
};
T* AsArray() { return &x; }
const T* AsArray() const { return &x; }
Vec3() {}
Vec3(const T a[3]) : x(a[0]), y(a[1]), z(a[2]) {}
@ -321,12 +317,6 @@ public:
#undef _DEFINE_SWIZZLER2
};
template<typename T, typename V>
Vec3<T> operator * (const V& f, const Vec3<T>& vec)
{
return Vec3<T>(f*vec.x,f*vec.y,f*vec.z);
}
typedef Vec3<float> Vec3f;
template<typename T>
@ -339,6 +329,7 @@ public:
};
T* AsArray() { return &x; }
const T* AsArray() const { return &x; }
Vec4() {}
Vec4(const T a[4]) : x(a[0]), y(a[1]), z(a[2]), w(a[3]) {}
@ -494,12 +485,6 @@ public:
#undef _DEFINE_SWIZZLER3
};
template<typename T, typename V>
Vec4<T> operator * (const V& f, const Vec4<T>& vec)
{
return Vec4<T>(f*vec.x,f*vec.y,f*vec.z,f*vec.w);
}
typedef Vec4<float> Vec4f;
@ -530,7 +515,7 @@ public:
}
template<typename T>
Vec3<T> operator * (const Vec3<T>& vec)
Vec3<T> operator * (const Vec3<T>& vec) const
{
Vec3<T> ret;
ret.x = values[0]*vec.x + values[3]*vec.y + values[6]*vec.z;
@ -539,7 +524,7 @@ public:
return ret;
}
Mat3x3 Inverse()
Mat3x3 Inverse() const
{
float a = values[0];
float b = values[1];
@ -555,7 +540,7 @@ public:
b*f-c*e, c*d-a*f, a*e-b*d) / Det();
}
BaseType Det()
BaseType Det() const
{
return values[0]*values[4]*values[8] + values[3]*values[7]*values[2] +
values[6]*values[1]*values[5] - values[2]*values[4]*values[6] -
@ -588,7 +573,7 @@ public:
}
template<typename T>
Vec4<T> operator * (const Vec4<T>& vec)
Vec4<T> operator * (const Vec4<T>& vec) const
{
Vec4<T> ret;
ret.x = values[0]*vec.x + values[4]*vec.y + values[8]*vec.z + values[12]*vec.w;
@ -615,6 +600,7 @@ inline void Vec3ByMatrix44(float vecOut[4], const float v[3], const float m[16])
vecOut[0] = v[0] * m[0] + v[1] * m[4] + v[2] * m[8] + m[12];
vecOut[1] = v[0] * m[1] + v[1] * m[5] + v[2] * m[9] + m[13];
vecOut[2] = v[0] * m[2] + v[1] * m[6] + v[2] * m[10] + m[14];
vecOut[3] = v[0] * m[3] + v[1] * m[7] + v[2] * m[11] + m[15];
}
inline void Vec4ByMatrix44(float vecOut[4], const float v[4], const float m[16])

View file

@ -572,7 +572,7 @@ static inline Vec4<int> GetTextureFunctionOutput(const Vec3<int>& prim_color_rgb
{
int t = (rgba) ? texcolor.a() : 255;
int invt = (rgba) ? 255 - t : 0;
out_rgb = (invt * prim_color_rgb + t * texcolor.rgb()) / 255;
out_rgb = (prim_color_rgb * invt + texcolor.rgb() * t) / 255;
out_a = prim_color_a;
break;
}

View file

@ -128,9 +128,9 @@ static VertexData ReadVertex(VertexReader& vreader)
for (int i = 0; i < vertTypeGetNumBoneWeights(gstate.vertType); ++i) {
Mat3x3<float> bone(&gstate.boneMatrix[12*i]);
tmppos += W[i] * (bone * ModelCoords(pos[0], pos[1], pos[2]) + Vec3<float>(gstate.boneMatrix[12*i+9], gstate.boneMatrix[12*i+10], gstate.boneMatrix[12*i+11]));
tmppos += (bone * ModelCoords(pos[0], pos[1], pos[2]) * W[i] + Vec3<float>(gstate.boneMatrix[12*i+9], gstate.boneMatrix[12*i+10], gstate.boneMatrix[12*i+11]));
if (vreader.hasNormal())
tmpnrm += W[i] * (bone * vertex.normal);
tmpnrm += (bone * vertex.normal) * W[i];
}
pos[0] = tmppos.x;

View file

@ -116,6 +116,7 @@ CGEDebugger::CGEDebugger(HINSTANCE _hInstance, HWND _hParent)
}
CGEDebugger::~CGEDebugger() {
CleanupPrimPreview();
delete flags;
delete lighting;
delete textureState;

View file

@ -64,6 +64,7 @@ private:
void SetupPreviews();
void UpdatePreviews();
void UpdatePrimPreview(u32 op);
void CleanupPrimPreview();
void UpdateSize(WORD width, WORD height);
void SavePosition();
void SetBreakNext(BreakNextType type);

View file

@ -261,6 +261,33 @@ void SimpleGLWindow::Draw(u8 *data, int w, int h, bool flipped, Format fmt) {
Redraw();
}
void SimpleGLWindow::GetContentSize(float &x, float &y, float &fw, float &fh) {
fw = (float)tw_;
fh = (float)th_;
x = 0.0f;
y = 0.0f;
if (flags_ & (RESIZE_SHRINK_FIT | RESIZE_CENTER) && !zoom_) {
float wscale = fw / w_, hscale = fh / h_;
// Too wide, and width is the biggest problem, so scale based on that.
if (wscale > 1.0f && wscale > hscale) {
fw = (float)w_;
fh /= wscale;
} else if (hscale > 1.0f) {
fw /= hscale;
fh = (float)h_;
}
}
if (flags_ & RESIZE_CENTER) {
x = ((float)w_ - fw) / 2;
y = ((float)h_ - fh) / 2;
}
x += offsetX_;
y += offsetY_;
}
void SimpleGLWindow::Redraw(bool andSwap) {
DrawChecker();
@ -284,27 +311,9 @@ void SimpleGLWindow::Redraw(bool andSwap) {
glBindTexture(GL_TEXTURE_2D, tex_);
glsl_bind(drawProgram_);
float fw = (float)tw_, fh = (float)th_;
float x = 0.0f, y = 0.0f;
if (flags_ & (RESIZE_SHRINK_FIT | RESIZE_CENTER) && !zoom_) {
float wscale = fw / w_, hscale = fh / h_;
// Too wide, and width is the biggest problem, so scale based on that.
if (wscale > 1.0f && wscale > hscale) {
fw = (float)w_;
fh /= wscale;
} else if (hscale > 1.0f) {
fw /= hscale;
fh = (float)h_;
}
}
if (flags_ & RESIZE_CENTER) {
x = ((float)w_ - fw) / 2;
y = ((float)h_ - fh) / 2;
}
x += offsetX_;
y += offsetY_;
float fw, fh;
float x, y;
GetContentSize(x, y, fw, fh);
const float pos[12] = {x,y,0, x+fw,y,0, x+fw,y+fh,0, x,y+fh,0};
static const float texCoords[8] = {0,0, 1,0, 1,1, 0,1};
@ -332,9 +341,15 @@ void SimpleGLWindow::Clear() {
void SimpleGLWindow::Begin() {
Redraw(false);
glDisableVertexAttribArray(drawProgram_->a_position);
glDisableVertexAttribArray(drawProgram_->a_texcoord0);
}
void SimpleGLWindow::End() {
glEnableVertexAttribArray(drawProgram_->a_position);
glEnableVertexAttribArray(drawProgram_->a_texcoord0);
Swap();
}

View file

@ -69,6 +69,24 @@ struct SimpleGLWindow {
SwapBuffers(hDC_);
}
int Width() {
return w_;
}
int Height() {
return h_;
}
int TexWidth() {
return tw_;
}
int TexHeight() {
return th_;
}
void GetContentSize(float &x, float &y, float &fw, float &fh);
static void RegisterClass();
protected:
void SetupGL();

View file

@ -15,17 +15,133 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "math/lin/matrix4x4.h"
#include "gfx_es2/glsl_program.h"
#include "Windows/GEDebugger/GEDebugger.h"
#include "Windows/GEDebugger/SimpleGLWindow.h"
#include "GPU/GPUInterface.h"
#include "GPU/Common/GPUDebugInterface.h"
#include "GPU/GPUState.h"
// TODO: Possibly a shader here to do the transforms?
static const char preview_fs[] =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"void main() {\n"
" gl_FragColor = vec4(1.0, 0.0, 0.0, 0.6);\n"
"}\n";
static const char preview_vs[] =
#ifndef USING_GLES2
"#version 120\n"
#endif
"attribute vec4 a_position;\n"
"uniform mat4 u_viewproj;\n"
"void main() {\n"
" gl_Position = u_viewproj * a_position;\n"
"}\n";
static GLSLProgram *previewProgram = NULL;
static GLSLProgram *texPreviewProgram = NULL;
static const GLuint glprim[8] = {
GL_POINTS,
GL_LINES,
GL_LINE_STRIP,
GL_TRIANGLES,
GL_TRIANGLE_STRIP,
GL_TRIANGLE_FAN,
// This is for RECTANGLES (see ExpandRectangles().)
GL_TRIANGLES,
};
static void BindPreviewProgram(GLSLProgram *&prog) {
if (prog == NULL) {
prog = glsl_create_source(preview_vs, preview_fs);
}
glsl_bind(prog);
}
static void SwapUVs(GPUDebugVertex &a, GPUDebugVertex &b) {
float tempu = a.u;
float tempv = a.v;
a.u = b.u;
a.v = b.v;
b.u = tempu;
b.v = tempv;
}
static void RotateUVThrough(GPUDebugVertex v[4]) {
float x1 = v[2].x;
float x2 = v[0].x;
float y1 = v[2].y;
float y2 = v[0].y;
if ((x1 < x2 && y1 > y2) || (x1 > x2 && y1 < y2))
SwapUVs(v[1], v[3]);
}
static void ExpandRectangles(std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices, int &count, bool throughMode) {
static std::vector<GPUDebugVertex> newVerts;
static std::vector<u16> newInds;
bool useInds = true;
size_t numInds = indices.size();
if (indices.empty()) {
useInds = false;
numInds = count;
}
// Will need 4 coords and 6 points per rectangle (currently 2 each.)
newVerts.resize(numInds * 2);
newInds.resize(numInds * 3);
u16 v = 0;
GPUDebugVertex *vert = &newVerts[0];
u16 *ind = &newInds[0];
for (size_t i = 0, end = numInds; i < end; i += 2) {
const auto &orig_tl = useInds ? vertices[indices[i]] : vertices[i];
const auto &orig_br = useInds ? vertices[indices[i + 1]] : vertices[i + 1];
vert[0] = orig_br;
// Top right.
vert[1] = orig_br;
vert[1].y = orig_tl.y;
vert[1].v = orig_tl.v;
vert[2] = orig_tl;
// Bottom left.
vert[3] = orig_br;
vert[3].x = orig_tl.x;
vert[3].u = orig_tl.u;
// That's the four corners. Now process UV rotation.
if (throughMode)
RotateUVThrough(vert);
// Build the two 3 point triangles from our 4 coordinates.
*ind++ = v + 0;
*ind++ = v + 1;
*ind++ = v + 2;
*ind++ = v + 3;
*ind++ = v + 0;
*ind++ = v + 2;
vert += 4;
v += 4;
}
std::swap(vertices, newVerts);
std::swap(indices, newInds);
count *= 3;
}
void CGEDebugger::UpdatePrimPreview(u32 op) {
const u32 prim_type = (op >> 16) & 0xFF;
const u32 count = op & 0xFFFF;
int count = op & 0xFFFF;
if (prim_type >= 7) {
ERROR_LOG(COMMON, "Unsupported prim type: %x", op);
return;
@ -39,12 +155,70 @@ void CGEDebugger::UpdatePrimPreview(u32 op) {
}
const GEPrimitiveType prim = static_cast<GEPrimitiveType>(prim_type);
static std::vector<GPUDebugVertex> vertices;
static std::vector<u16> indices;
if (!gpuDebug->GetCurrentSimpleVertices(count, vertices, indices)) {
ERROR_LOG(COMMON, "Vertex preview not yet supported");
return;
}
if (prim == GE_PRIM_RECTANGLES) {
ExpandRectangles(vertices, indices, count, gpuDebug->GetGState().isModeThrough());
}
float fw, fh;
float x, y;
frameWindow->Begin();
// TODO: Get the coords, render on top of the texture and framebuffer previews.
// TODO: glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);?
frameWindow->GetContentSize(x, y, fw, fh);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquation(GL_FUNC_ADD);
glBindTexture(GL_TEXTURE_2D, 0);
glViewport(x, y, fw, fh);
glScissor(x, y, fw, fh);
BindPreviewProgram(previewProgram);
Matrix4x4 ortho;
ortho.setOrtho(0, frameWindow->TexWidth(), frameWindow->TexHeight(), 0, -1, 1);
glUniformMatrix4fv(previewProgram->u_viewproj, 1, GL_FALSE, ortho.getReadPtr());
glEnableVertexAttribArray(previewProgram->a_position);
glVertexAttribPointer(previewProgram->a_position, 3, GL_FLOAT, GL_FALSE, sizeof(GPUDebugVertex), (float *)vertices.data() + 2);
if (indices.empty()) {
glDrawArrays(glprim[prim], 0, count);
} else {
glDrawElements(glprim[prim], count, GL_UNSIGNED_SHORT, indices.data());
}
frameWindow->End();
texWindow->Begin();
texWindow->GetContentSize(x, y, fw, fh);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquation(GL_FUNC_ADD);
glBindTexture(GL_TEXTURE_2D, 0);
glViewport(x, y, fw, fh);
glScissor(x, y, fw, fh);
BindPreviewProgram(texPreviewProgram);
ortho.setOrtho(0.0, 1.0, 1.0, 0.0, -1.0, 1.0);
glUniformMatrix4fv(texPreviewProgram->u_viewproj, 1, GL_FALSE, ortho.getReadPtr());
glEnableVertexAttribArray(texPreviewProgram->a_position);
glVertexAttribPointer(texPreviewProgram->a_position, 2, GL_FLOAT, GL_FALSE, sizeof(GPUDebugVertex), (float *)vertices.data());
if (indices.empty()) {
glDrawArrays(glprim[prim], 0, count);
} else {
glDrawElements(glprim[prim], count, GL_UNSIGNED_SHORT, indices.data());
}
texWindow->End();
}
}
void CGEDebugger::CleanupPrimPreview() {
glsl_destroy(previewProgram);
glsl_destroy(texPreviewProgram);
}