View Full Version : OpenGL port - help needed
patrickvl
February 22nd, 2011, 12:26
Hi there, some of you have already seen that I'm working on an OpenGL implementation, as OpenGL is far better suited for push-buffer emulation than D3D.
This is mainly due to the fact that D3D needs Index & Vertex buffers for almost everything, while OpenGL can render directly from pointers (using glVertexAttribPointer, glDrawArrays and glDrawElements) and supports immediate mode rendering.
Alas, I'm a complete newbie to OpenGL, so I could use some help. (StrikerX3 is already helping me out, testing a few things here and there. But like me, he's also new to OpenGL.)
So here a request : Does anyone here have experience with OpenGL and are you willing to help us out a little?
Right now the most important thing that I can't get going, is setting the correct viewport, and projection & model view matrices. (All this either with a simple shader or using the fixed-function pipeline.)
Please take a look at my current code (http://dxbx.svn.sourceforge.net/viewvc/dxbx/src/DxbxKrnl/EmuD3D8/uPushBuffer.pas?view=markup), perhaps you spot a problem or an incorrect assumption - any help is appreciated!
Bill_gates
February 23rd, 2011, 17:18
I wish i knew enough opengl to help... sometime in the future i gotta try my hand at 3d programming
blueshogun96
February 26th, 2011, 00:02
At your service!
JohnJack
February 26th, 2011, 02:45
I just saw on your blog that you were also trying to convert your project (cxbx) to OpenGL, with plans to use CG instead of ARB fragment programs. Are any of the XDK samples displaying?
blueshogun96
February 26th, 2011, 02:57
I'm testing it (the d3d8_xbox.dll) with the normal DirectX SDK first. So far, everything I added works just fine except lighting. There's no equivalent light parameter for "Range" in OpenGL, afaik.
JohnJack
February 26th, 2011, 10:52
I saw in this thread (http://www.gamedev.net/topic/482884-d3dlight8-range-equivalent-in-opengl/)(and you probably did too), that such calculations can be done in GLSL (since Opengl ARB assembly doesn't have if-statements).
blueshogun96
February 26th, 2011, 13:23
We'll need a fixed pipeline implementation because what if the game is already using a shader?
patrickvl
February 26th, 2011, 15:10
Enlighten me please; What part of the fixed function pipeline is still active when there's also a shader active?
As a sidenote : It seems the NV2A shader pipe doesn't apply the world/view/projection matrix transform yet - as with my push-buffer emulation code I've seen that the Xbox1 D3D implementation still uses a shader program internally when the fixed-functinon shader code contains D3DFVF_XYZRHW (it doesn't seem to do that in the D3DFVF_XYZ and D3DFVF_XYZB* cases). This fixed-function shader only applies multi-sample scaling & offsets; Here the code I got using my not-yet commited vertex shader decoder (the hexadecimal codes are what's put in the push-buffer slots dedicated for vertex-shader programs) :
// 00000000, 0020001B, 0836106C, 2F100FF8:
mov r1, v0;
// 00000000, 0420061B, 083613FC, 5011F818:
mov oD0, v3; // Note: Somehow, oD1 is not assigned?!?
rcp r1.w, r1.w;
// 00000000, 002008FF, 0836106C, 2070F828:
mov oFog, v4.w;
// 00000000, 0240081B, 1436186C, 2F20F824:
mul r2, r1, c[0]; // c[-96] in D3D speak - applies SuperSampleScale
// 00000000, 0060201B, 2436106C, 3070F800:
add r12, r2, c[1]; // c[-95] in D3D speak - applies SuperSampleOffset
// 00000000, 00200200, 0836106C, 2070F830:
mov oPts, v1.x;
// 00000000, 00200E1B, 0836106C, 2070F838:
mov oB0, v7;
// 00000000, 0020101B, 0836106C, 2070F840:
mov oB1, v8;
// 00000000, 0020121B, 0836106C, 2070F848:
mov oT0, v9;
// 00000000, 0020141B, 0836106C, 2070F850:
mov oT1, v10;
// 00000000, 0020161B, 0836106C, 2070F858:
mov oT2, v11;
// 00000000, 0020181B, 0836106C, 2070F861:
mov oT3, v12;
mov oPos, r12; // Note: This is needed as oPos is read-only (we use R12 above)
END;
The XDK docs also mention a "#pragma screenspace" directive that indicates that screenspace scale & offset are already handled by the shader, otherwise the following opcodes are added automatically :
mul r12.xyz, r12, c58; // c[-38] in D3D speak - see EmuNV2A_ViewportScale,
rcp r1.x, r12.w; // Originally RCC, but that's not supported in ARBvp1.0
mad r12.xyz, r12, r1.x, c59; // c[-37] in D3D speak - see EmuNV2A_ViewportOffset
In any case, as you can see there's no matrix multiplication (DP4) present in there, so that would mean the NV2A does matrix multiplication in a separate pass.
OpenGL however seems to expect me to do this matrix multiplication in my shader, which would mean every NV2A shader I convert will require an additional few opcodes for the a projection matrix multiplication.
Are my assumptions correct? I'm quite new to this all... TIA!
JohnJack
February 26th, 2011, 21:25
I was assuming that you would either have to do it multiple passes, or maybe prepend the fixed-function equivalent shaders before any shader included by the game. I'm not sure how multiple passes would work. I was trying to determine if the Transform Feedback (http://www.opengl.org/wiki/Transform_Feedback) extension (D3D10 Stream-Out) would help with this, but the sample tutorial (http://cvit.iiit.ac.in/index.php?page=resources) I downloaded doesn't work on ATI cards as it uses the NV_transform_feedback extension, but ATI only supports EXT_transform_feedback.
EDIT: It seems one needs to add a vertex shader to the tutorial for it to make use of the EXT_transform_feedback extension. I've made this modification. However, as EXT_transform_feedback only works with GLSL (not ARB assembly shaders), the current method of utilizing Direct3D8 binary shaders would need to be drastically changed. Anyways, the current problem is getting OpenGL primitives on the screen, all else is secondary :).
blueshogun96
February 28th, 2011, 01:53
So there's no fixed pipeline?
JohnJack
February 28th, 2011, 09:44
That would be my assumption. I'm not the implementer, but given that the fixed function pipeline (FFP) can be emulated with shaders, why do you need it? In the scenario where the game uses both, render the vertices into a transform feedback buffer using a vertex shader that emulates the FFP, then render the transformed vertices using the game's vertex shader.
blueshogun96
February 28th, 2011, 22:48
If there's no fixed pipeline, then that means that we won't have to worry about using OpenGL's fixed pipeline lighting functions! All of our lighting calculations can be done using the Xbox Direct3D's default shader programs if no custom vertex/fragment programs are being used.
EDIT: This is my 4034-th post, hopefully I can make good use out of my 4627-th post! :lol:
EDIT2: For !!ARBvp/fp1.0 programs, you MUST have instructions such as MOV, MUL, ADD, etc. in all caps. OpenGL will return an error if you dont! :) Btw, do you need help learning !!ARBvp/fp? I wrote some basic tutorials on both and they work rather well if you need them. Don't hesitate to ask!
Frog186
March 1st, 2011, 04:06
Hi All I just wanted to ask you all when the dxbx emulator is in use for old and new computers will opengl effect those computers without directx? I believe that directx is better than opengl because I don't have opengl but directx instead and the graphics on direct is better than opengl well that is my opinion sorry about this discussion I had to put this in what do others in this forum think?
I know opengl has been around for a long time before even directx has but I believe that directx patrick would be better than opengl but if you think otherwise than I will try and agree with you and others in this forum!
patrickvl
March 1st, 2011, 09:18
I *think* I understand what's playing a part here : The D3DFVF_XYZRHW flag indicates already-transformed vertices are going to be rendered - hence the lack of a matrix rotation in the shader. And the use of a shader is most likely the preferred way to prevent the fixed-function pipeline to apply unwanted mvp transformations. (I'm just guessing here, but an alternative method could be to reset the mvp matrices to the identity matrix... that would be more costly in terms of state-changes).
Bottom line : There *is* a fixed-function pipeline in the NV2A, and we still have to figure out how to map it to OpenGL properly.
JohnJack
March 1st, 2011, 11:06
Bottom line : There *is* a fixed-function pipeline in the NV2A, and we still have to figure out how to map it to OpenGL properly.
From my research, there is no matching OpenGL equivalent to D3DLIGHT8/9 Range member, so it either has to be ignored or emulated. The idea of emulating the fixed-function pipeline with shaders is shown in Microsoft's Direct3D10 FixedFuncEmu Sample (http://msdn.microsoft.com/en-us/library/ee416406(v=vs.85).aspx).
patrickvl
March 1st, 2011, 11:16
@blueshogun96 : I welcome all the help I can get - it's really frustrating working on this stuff and not understanding most of it :(
I hope you're tracking my push-buffer work; Last night I finally fixed the last few issues I was having with the push-buffer based vertex shader recompiler; All shaders I throw at it are now accepted by OpenGL, so at least there's some progress.
Alas, it doesn't really help getting anything drawn correctly. Here an example from the Vertices sample, which draws just 1 triangle like this :
struct CUSTOMVERTEX {
FLOAT x, y, z, rhw;
DWORD color; };
CUSTOMVERTEX g_Vertices[] = {
{ 320.0f, 150.0f, 0.5f, 1.0f, 0xffff0000, },
{ 420.0f, 330.0f, 0.5f, 1.0f, 0xff00ff00, },
{ 220.0f, 330.0f, 0.5f, 1.0f, 0xff00ffff, }};
SetStreamSource(0, g_pVB, sizeof(CUSTOMVERTEX));
SetVertexShader(D3DFVF_XYZRHW|D3DFVF_DIFFUSE);
DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
This sample doesn't even set any matrix, so when I look at the push-buffer commands I get this (just the interesting parts) :
NV2A Get=$0B7403AC 1/ 2: Method=0394 Data=00000000 NV2A_DEPTH_RANGE_NEAR
NV2A > DepthRange({0, 16777215}) > GL_PROJECTION_MATRIX={1, 0, 0, 0}{0, 1, 0, 0}{0, 0, 1, 0}{0, 0, 0, 1}
NV2A Get=$0B7408DC 3/ 3: Method=1D94 Data=000000F1 NV2A_CLEAR_BUFFERS
NV2A > ClearRect(0, 0, 639, 479) ClearColor={B:255, G:0, R:0, A:255} ClearZ=1.00 ClearStencil=0
NV2A Get=$0B740954 1/ 8: Method=0B80 Data=3F800000 NV2A_VP_UPLOAD_CONST(0)
NV2A > SetVertexShaderConstant(0, {1, 1, 16777215, 1}{0.53125, 0.53125, 0, 0})
NV2A Get=$0B740CD0 1/ 1: Method=17FC Data=00000005 NV2A_VERTEX_BEGIN_END
NV2A > DrawBegin(PrimitiveType=5{=D3DPT_TRIANGLELIST})
NV2A: New vertex shader decoded:
!!ARBvp1.0
TEMP R0,R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12;
ADDRESS A0;
ATTRIB v0 = vertex.attrib[0];
ATTRIB v1 = vertex.attrib[1];
ATTRIB v2 = vertex.attrib[2];
ATTRIB v3 = vertex.attrib[3];
ATTRIB v4 = vertex.attrib[4];
ATTRIB v5 = vertex.attrib[5];
ATTRIB v6 = vertex.attrib[6];
ATTRIB v7 = vertex.attrib[7];
ATTRIB v8 = vertex.attrib[8];
ATTRIB v9 = vertex.attrib[9];
ATTRIB v10 = vertex.attrib[10];
ATTRIB v11 = vertex.attrib[11];
ATTRIB v12 = vertex.attrib[12];
ATTRIB v13 = vertex.attrib[13];
ATTRIB v14 = vertex.attrib[14];
ATTRIB v15 = vertex.attrib[15];
OUTPUT oPos = result.position;
OUTPUT oD0 = result.color.front.primary;
OUTPUT oD1 = result.color.front.secondary;
OUTPUT oB0 = result.color.back.primary;
OUTPUT oB1 = result.color.back.secondary;
OUTPUT oPts = result.pointsize;
OUTPUT oFog = result.fogcoord;
OUTPUT oT0 = result.texcoord[0];
OUTPUT oT1 = result.texcoord[1];
OUTPUT oT2 = result.texcoord[2];
OUTPUT oT3 = result.texcoord[3];
PARAM c[] = { program.env[0..191] };
PARAM mvp[4] = { state.matrix.mvp };
MOV R1, v0;
MOV oD0, v3;
RCP R1.w, R1.w;
MOV oFog, v4.w;
MUL R2, R1, c[0];
MOV oD1, v4;
ADD R12, R2, c[1];
MOV oPts, v1.x;
MOV oB0, v7;
MOV oB1, v8;
MOV oT0, v9;
MOV oT1, v10;
MOV oT2, v11;
MOV oT3, v12;
MOV oPos, R12;
END
NV2A > DrawEnd() DrawPrimitive(VertexIndex=0, VertexCount=3) Float:{320, 150, 0.5, 1}{420, 330, 0.5, 1}{220, 330, 0.5, 1} ColorByte:{B:0, G:0, R:255, A:255}{B:0, G:255, R:0, A:255}{B:255, G:255, R:0, A:255}
So far everything looks good, it's just that I see only the blue (cleared) background, but no triangle... No matter how I initialize GL_MODELVIEW and GL_PROJECTION, the screen stays blank.
patrickvl
March 1st, 2011, 11:18
The idea of emulating the fixed-function pipeline with shaders is shown in Microsoft's Direct3D10 FixedFuncEmu Sample (http://msdn.microsoft.com/en-us/library/ee416406(v=vs.85).aspx).
I found another example for that called "Recreating OpenGL's Fixed Function Pipeline using Cg" here (http://www.codesampler.com/oglsrc/oglsrc_11.htm)
Nokiaman
March 1st, 2011, 11:47
Hi All I just wanted to ask you all when the dxbx emulator is in use for old and new computers will opengl effect those computers without directx? I believe that directx is better than opengl because I don't have opengl but directx instead and the graphics on direct is better than opengl well that is my opinion sorry about this discussion I had to put this in what do others in this forum think?
I know opengl has been around for a long time before even directx has but I believe that directx patrick would be better than opengl but if you think otherwise than I will try and agree with you and others in this forum!
1) OpenGL is better than DX (http://blog.wolfire.com/2010/01/Why-you-should-use-OpenGL-and-not-DirectX)
2) All GPUs still support OpenGL and it is currently at 4.1
3) OpenGL is cross-platform meaning easy porting to other platforms
4) All functions in DX10/11 were in OpenGL for a long time
That is all.
JohnJack
March 1st, 2011, 15:23
So far everything looks good, it's just that I see only the blue (cleared) background, but no triangle... No matter how I initialize GL_MODELVIEW and GL_PROJECTION, the screen stays blank.
It wouldn't matter what you do with the matrices, since neither are used in the vertex program (you simply assign it to mvp). I'll look into that code later and see what changes need to be made for it to work.
JohnJack
March 1st, 2011, 19:23
This vertex program should work with vertices specified in screen space (i.e. D3DFVF_XYZRHW). I simply converted Microsoft's FixedFuncEmu shader to GLSL, then use NVIDIA's CG compiler to convert it to ARB assembly. It would need small modifications to work with DXBX, but should get your triangle appearing on the screen :D. Without modification, the below code should produce an uncolored triangle, since it isn't getting color information from the same vertex attribute as dxbx.
PARAM c[2] = { { 0.5, 1 },#since PARAM c is also used in dxbx, name change required
program.local[1] };
MOV R0.xy, c[1]; #set R0.x = 640, R0.y = 480
MUL R0.y, R0, c[0].x;
MUL R0.z, R0.x, c[0].x;
RCP R0.x, R0.y;
RCP R0.y, R0.z;
MOV result.color, vertex.attrib[1]; #because I'm sending color information through vertex.attrib[1] (instead of vertex.attrib[3], like GL's immediate mode and dxbx)
MAD result.position.y, -vertex.attrib[0], R0.x, c[0];
MAD result.position.x, vertex.attrib[0], R0.y, -c[0].y;
MOV result.position.z, -vertex.attrib[0];
MOV result.position.w, c[0].y;
END
c[1] holds the value of the viewport, and is set with the following call
glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB ,1,640,480,0,1);
where it is assumed that the viewport size of 640x480. The GLSL equivalent for this shader is:
#version 330 compatibility
uniform vec4 viewport;
layout (location = 0) in vec4 Position; //glVertexAttribPointer(0, ...);glEnableVertexAttribArray(0);
layout (location = 1) in vec4 Color; //glVertexAttribPointer(1, ...); glEnableVertexAttribArray(1);
void main()
{
//The below code transforms screen coordinates into clip space
vec4 pos;
pos.x = (Position.x / (viewport.x/2.0)) -1;
pos.y = -(Position.y / (viewport.y/2.0)) +1;
pos.w = 1;
pos.z = -Position.z;
gl_Position = pos;
gl_FrontColor = Color;
}
and the value of viewport was set using:
int viewport = glGetUniformLocation(pg,"viewport");//assume pg is a valid program object
glProgramUniform4f(pg,viewport,640,480,0,1);//requires EXT_direct_state_access, else use glUniform4f
JohnJack
March 2nd, 2011, 16:10
I came across the following in NVIDIA's ARB Vertex Program tutorial presentation (http://developer.nvidia.com/docs/IO/8230/GDC2003_OGL_ARBVertexProgram.pdf). On page 54, the following is listed:
When a generic attribute is specified using glVertexAttrib*(), the current value for the corresponding conventional attribute becomes undefined Also true for the converse
Page 56 lists various conventional attributes (e.g. vertex.position, vertex.color), and their generic counterparts (vertex.attrib[0], vertex.attrib[3], respectively).
This would imply that when using deprecated features (e.g glColor4f, glColorPointer), the vertex program must reference conventional attributes (vertex.color), whilst attributes assigned by glVertexAttribPointer would reference the specific attribute index (vertex.attrib[]) to which they have been assigned. The only exception is vertex.attrib[0], which is aliased to vertex.position (according to the OpenGL 2 spec (http://www.opengl.org/sdk/docs/man/xhtml/glVertexAttrib.xml#description)).
patrickvl
March 2nd, 2011, 21:34
This would imply that when using deprecated features (e.g glColor4f, glColorPointer), the vertex program must reference conventional attributes (vertex.color), whilst attributes assigned by glVertexAttribPointer would reference the specific attribute index (vertex.attrib[]) to which they have been assigned.
Oh man! When will the hurting stop?
I was hoping that we would need to recompile each shader only once, but now we already have two variations :
- in cases where the NV2A seems to apply the mvp itself (without any mention of that in the shader), we have to append that rotation ourselves
- when a shader is used in immediate mode rendering, the attributes must be conventional - when we're rendering from pointers it should specify generic attributes.
I was thinking - instead of using glVertexAttribPointer, maybe we should use the (deprecated) conventional gl*Pointer functions as much as possible, so that the shader can be used for both rendering methods. (I really don't want to generate different versions of a shader for difference usage-scenarios). Any objections against this?
PS: Another solution could be to do what the D3D version of Cxbx and Dxbx does : Collect all immediate mode vertex data into a buffer and render that with one call. The advantage of that is, that everything can be drawn using glVertexAttribPointer (and thus allows us using just generic shader attributes), but it would require a bit of housekeeping - as only at the end of the data we know for sure which attributes where supplied.
This brings me to another question: I've seen shaders that use attributes that where not part of a stream - am I correct in assuming that the values set to these attributes using glVertexAttrib stay the unmodified per-vertex and can thus be seen as a few more constants?
JohnJack
March 2nd, 2011, 23:36
I was thinking - ... Any objections against this?
If using gl*Pointers is easier to maintain than using glVertexAttrib*, then by all means use it. I'm biased towards generic attributes. Maintaining 1 shader is better than 2. However, I don't understand the following:
... everything can be drawn using glVertexAttribPointer (and thus allows us using just generic shader attributes), but it would require a bit of housekeeping - as only at the end of the data we know for sure which attributes where supplied.
Is this the case with all rendering modes (immediate mode, vertex buffers), where the 'push buffer' sends you a heap of memory and on its tail is a description of what the data represents?
I've seen shaders that use attributes that where not part of a stream - am I correct in assuming that the values set to these attributes using glVertexAttrib stay the unmodified per-vertex and can thus be seen as a few more constants?
Is this behaviour defined in Direct3D8 for XBox? It sounds as though the attributes were part of the current state. The glVertexAttrib spec states (http://www.opengl.org/sdk/docs/man/xhtml/glVertexAttrib.xml#description):
The value of each generic vertex attribute is part of current state, just like standard vertex attributes, and it is maintained even if a different program object is used.
This means that execution order is important.
patrickvl
March 3rd, 2011, 08:02
Is this the case with all rendering modes (immediate mode, vertex buffers), where the 'push buffer' sends you a heap of memory and on its tail is a description of what the data represents?
When we're dealing with vertex-buffer rendering, the push-buffer receives commands that set the vertex attribute pointers, so there's not much to it, really. (There's a caveat here, but I'll talk about that later)
However in immediate mode, when the Begin command is received we don't know what kind of data setters will follow until we've received the End command. What I meant was, that we could collect all vertex data send to us in between those two calls, create buffers for each type, and draw that using vertex attribute pointers, so that we can suffice with just the vertex shader variant that's using generic attributes.
Is this behaviour defined in Direct3D8 for XBox?
The SDK docs don't mention this - but one of the samples (CompressedVertices) uses a vertex shader that reads v9 (Texcoords) without any mention of this in the sample code. (Although to be honest, this sample doesn't even use textures, so it might well be an oversight in the shader.) But the quote you gave on glVertexAttrib does indicate that attributes set with that API (and not supplied via a pointer) maintain their value, so they can indeed be seen as a constant.
About this caveat : The Xbox1 D3D implementation supports a few NV2A specific data types that are not available on the PC version of D3D8 (nor D3D9); In Dxbx we inherited code from Cxbx that converted those types to types that are supported;
D3DVSDT_NORMSHORT1 is converted to D3DVSDT_FLOAT2
D3DVSDT_NORMSHORT2 is converted to D3DVSDT_FLOAT2 (not for D3D9, as it does support D3DVSDT_NORMSHORT2)
D3DVSDT_NORMSHORT3 is converted to D3DVSDT_FLOAT4
D3DVSDT_NORMSHORT4 is converted to D3DVSDT_FLOAT4 (not for D3D9, as it does support D3DVSDT_NORMSHORT4)
D3DVSDT_NORMPACKED3 is converted to D3DVSDT_FLOAT3
D3DVSDT_SHORT1 is expanded to D3DVSDT_SHORT2
D3DVSDT_SHORT3 is expanded to D3DVSDT_SHORT4
D3DVSDT_PBYTE1 is converted to D3DVSDT_FLOAT1
D3DVSDT_PBYTE2 is converted to D3DVSDT_FLOAT2
D3DVSDT_PBYTE3 is converted to D3DVSDT_FLOAT3
D3DVSDT_PBYTE4 is converted to D3DVSDT_FLOAT4
D3DVSDT_FLOAT2H is converted to D3DVSDT_FLOAT4
Any idea how these should be mapped to OpenGL? (I suspect there's much less conversion needed, but it all depends on the available card capabilities.)
JohnJack
March 3rd, 2011, 09:36
What I meant was, that we could collect all vertex data send to us in between those two calls, create buffers for each type, and draw that using vertex attribute pointers, so that we can suffice with just the vertex shader variant that's using generic attributes.
Why create buffers for each type, when the gl*Pointer functions allow you to read from interleaved data?
But the quote you gave on glVertexAttrib does indicate that attributes set with that API (and not supplied via a pointer) maintain their value, so they can indeed be seen as a constant.
When it said just like standard attributes, they were referring to conventional attributes. Both are saved. It is similar to using one glColor call to set the color of all glVertex calls that follow.
About this caveat : The Xbox1 D3D implementation supports a few NV2A specific data types that are not available on the PC version of D3D8 (nor D3D9);...
OpenGL is well known for allowing allowing different data types to set conventional attributes (e.g. glColor4ub, glColor4i, glColor4s ...). Internally, they are converted to a float point number when accessed in the shader. True integer support only arrived with the advent of D3D10/OpenGL3-level hardware.
The glVertexAttribPointer spec states (http://www.opengl.org/sdk/docs/man/xhtml/glVertexAttribPointer.xml):
... type specifies the data type of each component, and stride specifies the byte stride from one attribute to the next, allowing vertices and attributes to be packed into a single array or stored in separate arrays. If set to GL_TRUE, normalized indicates that values stored in an integer format are to be mapped to the range [-1,1] (for signed values) or [0,1] (for unsigned values) when they are accessed and converted to floating point. Otherwise, values will be converted to floats directly without normalization.
So you can continue to do the conversion yourself (as you've done for D3D9), or let OpenGL do it for you. With the exception of NORMPACKED3 (I think) and FLOAT2H, you just have to set the relevant parameters of glVertexAttrib(Pointer) to handle your data.
The documentation (http://www.opengl.org/sdk/docs/man/) for these functions has all of the information you need.
patrickvl
March 3rd, 2011, 12:31
Why create buffers for each type, when the gl*Pointer functions allow you to read from interleaved data?
Because in immediate mode rendering, the vertex-data is delivered via SetVertexData calls and pushed directly into the push-buffer. So we cannot 'just' set a pointer and a stride, as the calls can be ordered differently per vertex. Also, some components (like colors or point-sizes) could appear less frequently than the number of vertices being drawn.
So *if* we're going to convert immediate-mode rendering to buffer-based rendering (to simplify the vertex shader recompiling), it would mean building up buffers for each attribute that's written to between the first and last vertex position (attribute values send prior to the first vertex position can be set directly using glVertexAttrib of course, so these won't need a buffer).
Also note in this scenario that all changing attributes will need to have a specific value alongside each vertex position, or else the buffers won't line up anymore. This implies lots of repeating values (especially for attributes that don't change all that much) - sure it's overhead, but it's the only way to get this working. (It's either that, or juggling with various vertex shader variants.)
When it said just like standard attributes, they were referring to conventional attributes. Both are saved. It is similar to using one glColor call to set the color of all glVertex calls that follow.
Got it, thanks.
With the exception of NORMPACKED3 (I think) and FLOAT2H, you just have to set the relevant parameters of glVertexAttrib(Pointer) to handle your data.
Yeah, the flexibility in this regard is one of the reasons that OpenGL is preferable to D3D. (I did look into your statement that D3D9 is also capable of pointer-based vertex stream buffers, but I couldn't corroborate that - as far as I can tell, you still need to make a copy - something I'd rather avoid.)
By the way, if we decide to keep immediate-mode rendering (and thus don't collect vertex data values into buffers) the unsupported data-types (NORMPACKED3 and FLOAT2H) won't bite us, as the various SetVertexData calls don't support these types (pfew!)
JohnJack
March 3rd, 2011, 13:04
I did look into your statement that D3D9 is also capable of pointer-based vertex stream buffers, but I couldn't corroborate that - as far as I can tell, you still need to make a copy - something I'd rather avoid.
Yes, a copy to a dynamic vertex buffer would be required (similar to VBOs in OpenGL). But I never saw copying data to GPU/AGP memory as an issue. I was referring to the techniques discussed on this page:
Programming One or More Streams (Direct3D 9) (Windows) (http://msdn.microsoft.com/en-us/library/bb147299(v=vs.85).aspx)
Btw, converting all of your rendering code to use conventional attributes would be easier. You would just have to modify your shader to use conventional attributes.
patrickvl
March 3rd, 2011, 13:43
Oh, it's not the copying, but the accompanying conversions that I want to avoid!
For example, the 'Cartoon' sample (showing a yellow cartoon-shaded Robot) dropped from 60 fps to 7 fps when I started converting D3D vertex buffers on every frame. I had to do that in my 'less patching' approach (based on D3D8), which is on-hold right now since I'm researching this push-buffer emulation using OpenGL. Sure, a CRC based cache can alleviate that of course, but I'd rather switch over to OpenGL entirely.
patrickvl
March 3rd, 2011, 16:08
converting all of your rendering code to use conventional attributes would be easier. You would just have to modify your shader to use conventional attributes.
Could you explain why conventional attributes are easier? As I understand, conventional setting attributes would at least require the correct call for each attribute (glColorPointer, glNormalPointer, glVertexPointer, etc.) to set vertex data pointers with. Using glVertexAttribPointer sounds easier...
Or are you referring to the fact that immediate-mode drawing requires no buffering if we use conventional attributes in the recompiled shader? I can see the logic in that, but there's one little problem to solve in that approach:
Unmapped attributes;
For most vertex attributes, there is a conventional setter, but vertex.attrib[6] and [7] have no setter. Also, if the card only supports 4 texture channels, vertex.attrib[13], [14] and [15] are also not accessible using conventional setters. And then there's the restriction on allowed GL calls between glBegin/glEnd (http://www.opengl.org/registry/specs/ARB/vertex_shader.txt) :
The only GL commands that are allowed within any Begin/End pairs are the commands for specifying vertex coordinates, vertex colors, normal coordinates, texture coordinates, generic vertex attributes and fog coordinates (Vertex, Color, SecondaryColor, Index, Normal, TexCoord and MultiTexCoord, VertexAttrib*ARB, FogCoord)
Perhaps we should divert to generic attributes when a slot is not covered by a conventional attribute? (Surely they can be used alongside each other in one and the same shader?)
patrickvl
March 3rd, 2011, 16:16
Wait a minute - there's another solution possible too! Instead of going with conventional shader inputs, just to support immediate mode rendering, we could instead use generic attributes by mapping the immediate mode data onto generic attributes, so that a glColor(...) call becomes a glVertexData(3, ...) call, etc. That would allow all inputs, still takes only one vertex shader variant and wouldn't require a buffer for immediate mode rendering! Would that be possible/wise?
JohnJack
March 3rd, 2011, 16:43
we could instead use generic attributes by mapping the immediate mode data onto generic attributes, so that a glColor(...) call becomes a glVertexData(3, ...) call, etc
Yes, glVertexAttrib will work, as it can be called between glBegin/glEnd. Great idea :)! The flexibility of OpenGL is one of the reasons many implementations are generally slower than their Direct3D counterparts.
Regarding your earlier question.
Applications that mix conventional and generic vertex attributes in a single rendering pass should be careful to avoid using attributes that may alias. To limit inadvertent use of such attributes, loading a vertex program that used a pair of attributes that may alias is guaranteed to fail. Applications requiring a small number of generic vertex attributes can always safely use generic attributes 6 and 7, and any supported attributes corresponding to unused or unsupported texture units. For example, if an implementation supports only four texture units, generic attributes 12 through 15 can always be used safely.
So it is possible to mix generic attributes with conventional ones, as long as they don't alias one another.
Multitexturing isn't as simple using TexCoordPointer as it is with using VertexAttribPointer, as you have to specify the active texture unit (http://www.opengl.org/resources/code/samples/sig99/advanced99/notes/node61.html) that uses your texture coordinates. If an implementation supports EXT_direct_state_access, MultiTexCoordPointerEXT could be used to alleviate that problem. However, that extension is not supported by current legacy products from AMD or NVIDIA (pre-Geforce 6 and pre-Radeon HD cards), nor is it supported by Intel. Anyway, it is unlikely that your emulator will run on a GPU whose OpenGL implementation cannot handle 8 texture coordinate sets.
One conventional attribute that isn't supported on most graphics cards is vertex.weight, as few cards (atleast on Windows) support ARB_vertex_blend. Thus it can only be set using the attribute pointer (+1 for generic attributes).
The main benefit of conventional attributes is that it improves the readability of the code. Generic attributes are forward compatible (supported in the core profiles of OpenGL 3+), although this has little meaning if deprecated functionality continues to be supported (not a bad thing).
patrickvl
March 3rd, 2011, 18:33
Oops, I just realised that using glVertexAttrib will probably not work with the fixed function pipeline!
I fear we'll have to settle for a mixed shader : All conventional attributes as-is, all other slots using generic attributes, even though it's not advised (as stated page 56 here (http://developer.nvidia.com/docs/IO/8230/GDC2003_OGL_ARBVertexProgram.pdf)).
JohnJack
March 3rd, 2011, 18:44
Oops, I just realised that using glVertexAttrib will probably not work with the fixed function pipeline!
Err ... weren't you planning on using shaders to emulate the FFP? The benefit of using conventional attributes was that it allowed shaders access to values that were set by the FFP. Btw, Example Program 2 (pages 50-51) shows how to emulate fixed function lighting.
patrickvl
March 3rd, 2011, 19:25
Err ... weren't you planning on using shaders to emulate the FFP? The benefit of using conventional attributes was that it allowed shaders access to values that were set by the FFP. Btw, Example Program 2 (pages 50-51) shows how to emulate fixed function lighting.
In due time, yes, but it's a can of worms I don't want to open up yet. (And besides, first I have to discover how the NV2A fixed function pipeline actually works - what steps are done when exactly).
Actually, it's quite simple to make the code conditionally compile either to use generic attributes or conventional attributes; I've done most of the work already (http://dxbx.svn.sourceforge.net/viewvc/dxbx?view=revision&sortby=rev&revision=1611)
Edit : Here's the final switch. (http://dxbx.svn.sourceforge.net/viewvc/dxbx?view=revision&sortby=rev&revision=1612) As I said : not much code.
JohnJack
March 3rd, 2011, 22:38
first I have to discover how the NV2A fixed function pipeline actually works - what steps are done when exactly.
Maybe blueshogun can provide some insight, as he has some screenshots on his website with Cxbx using D3D8. Another source of information is the WINE project, which has spent the last decade layering D3D8 (http://wiki.winehq.org/DirectX-ToDo?action=AttachFile&do=get&target=pipeline-8.1.png)/9 on top of OpenGL, so their codebase should provide more insight into translating D3D8 to OpenGL (minus the differences that are specific to the NV2A).
EDIT: On looking at your code, I noticed that you commented out the glScalef call that is required to make the coordinate system of OpenGL left-handed. The transformation shader does not take this into account either. Is this handled elsewhere in your code? If you focus on pure fixed function vertex processing, where you know the inputs, and the expected output, you should be able to make the necessary transformations to the contents in the push-buffer to make the result appear on the screen.
HackerNoobKid
March 4th, 2011, 00:59
JohnJack is right about WINE project, they really have good info about layering D3D8/9 on top of OpenGL. It is good a way of obtaining information about it ;)
Shock120
March 4th, 2011, 03:22
Could asking around on OpenGL.org (http://www.opengl.org/discussion_boards/) help?
About the OpenGL.org website (http://www.opengl.org/about/)
OpenGL.org is a vendor-independent and organization-independent web site that acts as one-stop hub for developers and consumers for all OpenGL news and development resources. It has a very large and continually expanding developer and end-user community that is very active and vested in the continued growth of OpenGL. There are discussion boards, news groups and a variety of other venues for learning how to code using OpenGL, getting feedback on your projects, job opportunities, and support for the consumer trying to play a 3D gameI hope there are people nice enough to help. :D
JohnJack
March 5th, 2011, 13:37
I saw in Revision 1619 of your push buffer code:
Disabled conventional vertex attributes, as we will probably be using a shader instead of the fixed function anyway.
Yaay :). Plus, you also imported some stuff from WINE. Is it working in the way you expect?
patrickvl
March 5th, 2011, 16:07
Well, yes and no;
If I reproduce the 'Vertices' SDK sample in a test app, the wined3d 'transform_projection' code works for both immediate and deferred rendering (with a simple shader) and for immediate mode (without a shader). (Deferred rendering without a shader doesn't show up, I assume that's only logical because the fixed-function pipeline doesn't handle generic vertex attrib pointers.)
However, when I run the Vertices sample inside Dxbx I still see nothing. The problem is, that I had to alter a few things in the test app to get things rendering:
- The 'SuperSampleScale' z component send to the Xbox push-buffer is 16777215, which needs to be scaled down to 1 to get something on-screen.
- Also, the shader needs to be extended with a mvp transformation (although I wouldn't expect that to be necessary...)
On the bright side, the projection-view matrix used by the Vertices sample when running inside Dxbx is identical to to one in the test-application, so that part seems to be good now.
WineD3D does alter ARB shaders too, so I hope to find the issue sooner rather than later ;-)
JohnJack
March 5th, 2011, 18:38
- The 'SuperSampleScale' z component send to the Xbox push-buffer is 16777215, which needs to be scaled down to 1 to get something on-screen.
Did this sample work in your D3D implementation?
I noticed on the previous page that you had:
NV2A > SetVertexShaderConstant(0, {1, 1, 16777215, 1}{0.53125, 0.53125, 0, 0})
Does the Vertices sample make this call, or the D3D runtime internally? Try changing the far clip plane in your Frustum/Ortho calls to this value.
e.g.
glMatrixMode(GL_PROJECTION);
glOrtho (0,640,480,0,0,16777215);
- Also, the shader needs to be extended with a mvp transformation (although I wouldn't expect that to be necessary...)
Yes, that would be required as D3D's near and far clip plane is different from OpenGL's ... which maybe is why WineD3D alters the shaders as well (just guessing).
patrickvl
March 5th, 2011, 20:51
Previously, emulation worked by patching almost all D3D API's, forwarding them to native D3D8. This worked good enough to get 5 games in the 'playable' state, but that was about the best I could get it.
Since then I've been looking for ways to improve compatibility. First, I stopped patching many API's, so that more Xbox1 code ran unmodified. This actually improved compatibility to a level that made all (but one) SDK samples run correctly! (However, games where worse off than before.)
The lesson I learned, was that less patching means behaving closer to the original, so I took the bull by the horn, removed all D3D patches and started on push-buffer level emulation. I discovered soon enough that implementing push-buffer commands via D3D was going to be problematic at best, hence my switch to OpenGL.
Even though I don't see any graphics on-screen yet, the OpenGL API does turn out to be a much better fit for the NV2A commands - many commands can be forwarded to OpenGL with little or no argument-modifications.
About the constants - the Xbox1 D3D runtime sends these to the GPU, as they are used by the 'passthrough' shader (which is send by the D3D runtime for rendering D3DFVF_XYZRHW vertex data without a user-defined shader).
There are 4 of these constants, one set (0 and 1) contains the SuperSample-Scale & -Offset respectively, the other set (58 and 59) constains the Viewport-Scale & Offset respectively.
The SuperSample constants are accessed by the 'passthrough' shader, the Viewport constants are used by a small piece of code that gets added to all user-defined shaders that have no '#pragma screenspace' directive. (The 'passthrough' shader doesn't have this extra piece).
To be complete - here's the bit that gets added (R12 will be written to oPos afterwards):
// This part applies the screen-space transform :
MUL R12.xyz, R12, c[134]; // c[-38] in D3D speak - ViewportScale,
RCP R1.x, R12.w; // Originally RCC, but that's not supported in ARBvp1.0
MAD R12.xyz, R12, R1.x, c[133]; // c[-37] in D3D speak - ViewportOffset
Anyway, I'll focus my research on the clip-planes now, I really hope to reach a breakthrough soon!
vicviper1974
March 8th, 2011, 13:58
Your da poop patrickvl. Just wanted you to know that.
JohnJack
March 16th, 2011, 20:35
I saw this thread (http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=293467&page=1) over at the OpenGL.org forums, and it may interest you if you decide to use VBOs. From the looks of it, STREAM buffers are faster than using gl*Pointer functions.
patrickvl
March 17th, 2011, 08:39
I saw this thread (http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=293467&page=1) over at the OpenGL.org forums, and it may interest you if you decide to use VBOs. From the looks of it, STREAM buffers are faster than using gl*Pointer functions.
That's an interesting read, but there's a few gotcha's that should be mentioned;
It's faster only for NVidia cards (ATI seems not to be affected by this flag) and the comparison was made using conventional vertex attributes - there's no mention whether this whole story applies to generic attributes too or not.. (Conventional attributes are old-fashioned nowadays, OpenGL has moved on to generic attributes, or at least so the specs say. Don't know what this means for the drivers though.)
JohnJack
March 17th, 2011, 13:00
On the fourth page, the developer states:
ATI VA = 56 fps
NVidia VA = 9 fps
ATI VBO STREAM = 200+ fps
NVidia VBO STREAM = 200+ fps
From what we've seen in the past few weeks, conventional attributes can be emulated via generic attributes. Both glVertexAttribPointer and glVertex/Color/NormalPointer work with VBOs as their last parameter is used as an offset. Given that current standards (OGL3+/D3D10+) have focused on buffers in GPU memory rather than system memory, they are future proof. Only CAD-like applications seem to prefer system memory pointers.
patrickvl
March 17th, 2011, 14:15
You got a point there - it seems both major vendors speed up significantly when using VBO + GL_STREAM_DRAW_ARB. Once I fix all transformation & viewport issues, I will try a switch to this rendering method.
However, I do wonder : What happens to performance if the entire VBO is constantly destroyed and re-created? And/or what if the pointers themselves are constantly altered?
This is probably what my most common usage-pattern will be :
The vertex-data is either coming indirectly from a relatively static D3D VertexBuffer, indicated via a pointer, or the data is put in-place in the push-buffer - to which I can still get a pointer (unless the vertex data was split up over multiple header+batch tuples, in which case I have no choice but to collect all these batches into another, contiguous, buffer myself.)
One would expect that GL_DYNAMIC_DRAW_ARB would perform better for the pointer-based rendering, but the thread you mentioned seems to indicate otherwise. Strange.
Also, how's the OpenGL driver going to make a distinction between GL_STREAM_DRAW_ARB and GL_DYNAMIC_DRAW_ARB - does it calculate a CRC in the DYNAMIC case or something, so that it can detect periods of static data and as such prevent an upload to GPU? (STREAM mode would upload the vertex data at every draw - which I would expect *not* to give a performance improvement over the other hint flags. Still strange that the VA approach is so much slower, then.)
Bill_gates
March 23rd, 2011, 20:41
any luck getting something to show?
patrickvl
March 23rd, 2011, 20:52
Nope, I'm taking a break from Dxbx for a while, as it was starting to cost me my health (staying up way too late for 3 years in a stretch has become a bit too much, or so my head seems to tell me). I still want to continue with it though, but I first have to regain my motivation. In the mean time I'm messing around with some other interesting stuff (http://codegolf.stackexchange.com/users/907/patrickvl).
JayFoxRox
March 28th, 2011, 00:12
Ah sucks to hear that patrick.
Was hoping to get some help with the stuff you send me (Thanks again by the way!) as I spend almost one week labeling it and developing tools to do various things (Mostly network and GPU related).
I also started low-level emulation of the GPU now but used GLSL from the very beginning because it seems to have better support and tends to be faster, especially with the small amount of recompilations needed in xbox games.
patrickvl
March 28th, 2011, 07:24
Ah sucks to hear that patrick.
Was hoping to get some help with the stuff you send me (Thanks again by the way!) as I spend almost one week labeling it and developing tools to do various things (Mostly network and GPU related).
I also started low-level emulation of the GPU now but used GLSL from the very beginning because it seems to have better support and tends to be faster, especially with the small amount of recompilations needed in xbox games.
Good to hear you found use for it! Anyway, I'm not leaving Xbox emulation; I just have to regain some strength and find a little more balance between this and other basic real life-related stuff, like sleep and stuff. :D
Just shoot me an email for whatever you'd want further explained/clarified.
vBulletin® v3.8.7, Copyright ©2000-2013, vBulletin Solutions, Inc.