PDA

View Full Version : Locking a VBO in OpenGL



Brainer
29-05-2008, 05:31 AM
:arrow:System: Windows Vista, Pentium D 2.66GHz, GeForce 7600 GS
:arrow:Compiler/IDE: Delphi 2007 for Win32
:arrow:API: OpenGL

Hello everyone! :)

I have a little problem with my VBOs. One friend asked me to make a OpenGL version of his VBO implementation in OpenGL. And I'm stuck, I don't really know how to do it. Can you please take a look at the two codes and tell me what's wrong?

HIS VERSION (DX)

TBVertexBufforDx9 = class(TBVertexBuffor)
private
VBuffor : IDIRECT3DVERTEXBUFFER9;
fscreen : TBScreenDx9;
public
procedure UnInit; override;
procedure CreateVertexBuffor(size : integer; sizevertex : integer; FVF : DWORD; Pool : TBPOOL = BPOOL_MANAGED; Usage : TBUsage = BUSAGE_WRITEONLY); override;
procedure Render(typ : TBShapetype; count : DWORD); override;

function Lock(start, count : DWORD) : pointer; override;
procedure UnLock; override;

destructor Destroy; override;
end;

function BUageToDxUsage(const usage : TBUsage) : cardinal; inline;
begin
case usage of
BUSAGE_RENDERTARGET: result := D3DUSAGE_RENDERTARGET;
BUSAGE_DYNAMIC: result := D3DUSAGE_DYNAMIC;
BUSAGE_WRITEONLY: result := D3DUSAGE_WRITEONLY;
end;
end;

procedure TBVertexBufforDx9.CreateVertexBuffor(size : integer; sizevertex : integer; FVF : DWORD; Pool : TBPOOL = BPOOL_MANAGED; Usage : TBUsage = BUSAGE_WRITEONLY);
var hr : HRESULT;
begin
if fscreen.device=nil then
raise EBNotInit.Create('screen not init');
hr := fscreen.Device.CreateVertexBuffer( size * sizevertex,
BUageToDxUsage(Usage), BFVF_CUSTOMVERTEX,
_D3DPOOL(Pool), VBuffor,nil );
if FAILED(hr) then //D3DPOOL_MANAGED
begin // D3DUSAGE_WRITEONLY
{$IFOPT D+}
if TheLoger<>nil then TheLoger.Write('Render Init ', DXGetErrorString9A(hr) , LogFatalError);
{$ENDIF}
raise EBNotInit.Create('Nie mo¬øna zainicjowa?¶ Rendera');
end;
fFVF := FVF;
fsizeVertex := sizevertex;
end;

procedure TBVertexBufforDx9.Render(typ : TBShapetype; count : DWORD);
begin
fscreen.Device.SetStreamSource( 0, VBuffor, 0, fsizeVertex );
fscreen.Device.SetFVF(fFVF);
fscreen.Device.DrawPrimitive( _D3DPRIMITIVETYPE(typ), 0, count );
end;

function TBVertexBufforDx9.Lock(start, count : DWORD) : pointer;
var s : dword;
begin
s := start*fsizeVertex;
VBuffor.Lock(s,s+fsizeVertex*count,result,0);
end;

procedure TBVertexBufforDx9.UnLock;
begin
VBuffor.Unlock;
end;

procedure TBVertexBufforDx9.UnInit;
begin
VBuffor := nil;
end;

destructor TBVertexBufforDx9.Destroy;
begin
UnInit;
inherited;
end;


MY VERSION (OGL)

{ .: TBVertexBufforOGL :. }
TBVertexBufforOGL = class(TBVertexBuffor)
private
{ Private declarations }
VBuffor: GLuint;
FScreen: TBScreenOGL;
public
{ Public declarations }
destructor Destroy(); override;

procedure UnInit(); override;
procedure CreateVertexBuffor(Size: Integer; SizeVertex: Integer;
FVF: DWORD; Pool: TBPOOL = BPOOL_MANAGED;
Usage: TBUsage = BUSAGE_WRITEONLY); override;

procedure Render(Typ: TBShapetype; Count: DWORD); override;

function Lock(Start, Count: DWORD): Pointer; override;
procedure UnLock(); override;
end;

{ TBVertexBufforOGL }

{ .: BUsageToOGLUsage :. }
function BUsageToOGLUsage(const Usage: TBUsage): GLuint; inline;
begin
case Usage of
BUSAGE_RENDERTARGET: Result := GL_STATIC_DRAW_ARB;
BUSAGE_DYNAMIC: Result := GL_DYNAMIC_DRAW_ARB;
BUSAGE_WRITEONLY: Result := GL_WRITE_ONLY_ARB;
end;
end;

procedure TBVertexBufforOGL.CreateVertexBuffor(Size, SizeVertex: Integer;
FVF: DWORD; Pool: TBPOOL; Usage: TBUsage);
begin
glGenBuffersARB(1, @VBuffor);

glBindBufferARB(GL_ARRAY_BUFFER_ARB, VBuffor);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, Size * SizeVertex, nil,
BUsageToOGLUsage(Usage));

FSizeVertex := SizeVertex;
end;

destructor TBVertexBufforOGL.Destroy;
begin
UnInit();

inherited Destroy();
end;

function TBVertexBufforOGL.Lock(Start, Count: DWORD): Pointer;
begin
Result := glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
end;

procedure TBVertexBufforOGL.Render(Typ: TBShapetype; Count: DWORD);
var
TheType: GLuint;
begin
glEnableClientState(GL_VERTEX_ARRAY);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, VBuffor);
case Typ of
BPOINTLIST: TheType := GL_POINTS;
BLINELIST: TheType := GL_LINES;
BLINESTRIP: TheType := GL_LINE_STRIP;
BTRIANGLELIST: TheType := GL_TRIANGLES;
BTRIANGLESTRIP: TheType := GL_TRIANGLE_STRIP;
BTRIANGLEFAN: TheType := GL_TRIANGLE_FAN;
end;
glDrawElements(TheType, Count, GL_UNSIGNED_INT,
Pointer(Count * SizeOf(DWORD)));
end;

procedure TBVertexBufforOGL.UnInit;
begin
glDeleteBuffersARB(1, @VBuffor);
end;

procedure TBVertexBufforOGL.UnLock;
begin
glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
end;


Everytime I execute this code, I get an AV. What's wrong? :? I think it has something to do with Lock and UnLock method, but I'm not sure.

Thank you in advance.

chronozphere
29-05-2008, 08:39 AM
Generaly, this kind of problem can be solved using breakpoints and stepping through your code. Have you done that? :?

I might have missed it, but what code do you use to utilise this class? You can expiriment with that a little bit. Just create the VBO and lock/unlock it without moving data. If that works, you can try to move data. If that works, it's probably the render method that bugs. :)

I alway's use these techniques to isolate bugs. Just make a simple testbed and call the routines you want to test. ;)

Good luck!

User137
29-05-2008, 12:29 PM
I experimented with arrays before, topic's here:
http://www.pascalgamedevelopment.com/viewtopic.php?t=4785
See if there's some differences. Though same program does raw rendering, displaylists, vertexarrays and vertexbuffer objects, it is commented well.

JSoftware
29-05-2008, 12:37 PM
Dumb question: Are you 100% certain that the relevant extensions have been loaded when you use these functions?

chronozphere
29-05-2008, 01:39 PM
@JSoftware: Good one! ;) because calling an uninitialized procvar result's in an AV.

Brainer
30-05-2008, 02:51 AM
Dumb question: Are you 100% certain that the relevant extensions have been loaded when you use these functions?
Yip, I'm 100% sure. :)


I experimented with arrays before, topic's here:
http://www.pascalgamedevelopment.com/viewtopic.php?t=4785
See if there's some differences. Though same program does raw rendering, displaylists, vertexarrays and vertexbuffer objects, it is commented well.

I tried your code, but I can't really make it work with my class. :? The problem is that I still get an AV.



I might have missed it, but what code do you use to utilise this class? You can expiriment with that a little bit. Just create the VBO and lock/unlock it without moving data. If that works, you can try to move data. If that works, it's probably the render method that bugs. :)

I don't understand. How to lock and unlock a VBO?

chronozphere
30-05-2008, 02:27 PM
Lol... the DirectX routines for this are called lock/unlock. These allow you to temporarly gain acces to the Vertexdata so you can modify it. The title of your thread mentions "locking" so i thought you would understand.

The openGL equalivents are:
glMapBufferARB
glUnmapBufferARB

Hope this helps. :)

Brainer
30-05-2008, 06:12 PM
Okay, but when I use them, I get an AV. :-/ Dunno what's wrong... :? This is the code that uses Lock procedure:

function TBRender.BeginRender(typ : TBShapeType; size : word; ile : word; BlendMode : TBBlendMode) : pointer;
var pvertex : pointer;
s : dword;
begin
if fsize+size>=PBUFSIZE then
Render;

if (typ = BTRIANGLESTRIP) or (typ=BTRIANGLEFAN) or (typ=BLINESTRIP) then
render
else if typ<>fType then
render;
if BlendMode<>fBlendMode then
begin
render;
fBlendMode := BlendMode;
end;
ftype := typ;
s:= fsize*sizeof(TBVertex2D);
pvertex := fbuffor.Lock(s,s+sizeof(TBVertex2D)*size) ;
inc(files, ile);
inc(fsize, size);
result := pvertex;
end;


But it isn't executed, I get AV. Anyone knows why? What could be wrong?

User137
31-05-2008, 10:09 AM
Ok 1 more thing

glDrawElements(TheType, Count, GL_UNSIGNED_INT,
Pointer(Count * SizeOf(DWORD)));

Make sure your int type is accurate. GL_UNSIGNED_INT is propably 32 bit where your data must also be 32 bit. So AV can occur if glDrawElements tries to read out of your memory.

Brainer
31-05-2008, 11:12 AM
Still the same. I even tried glDrawArrays instead, but I still get that god-damn AV. :?

chronozphere
31-05-2008, 03:21 PM
Hmm... you should try and set a breakpoint somewhere. :) Step through your code and pinpoint the exact location of the bug.

I could help you fix this, but i need you to get Online (MSN). :razz:

User137
31-05-2008, 04:33 PM
Still the same. I even tried glDrawArrays instead, but I still get that god-damn AV. :?
Could you paste your array declaration and code where pointers (both vertex and index buffers) are set to VBO.

Brainer
31-05-2008, 05:14 PM
I could help you fix this, but i need you to get Online (MSN). :razz:
I'm online all the time, but I'm using an offline mode. :)

User137, I'm not sure what you mean, I'm posting this:

{ TBVertexBufforOGL }

{ .: BUsageToOGLUsage :. }
function BUsageToOGLUsage(const Usage: TBUsage): GLuint; inline;
begin
case Usage of
BUSAGE_RENDERTARGET: Result := GL_STATIC_DRAW_ARB;
BUSAGE_DYNAMIC: Result := GL_DYNAMIC_DRAW_ARB;
BUSAGE_WRITEONLY: Result := GL_WRITE_ONLY_ARB;
end;
end;

procedure TBVertexBufforOGL.CreateVertexBuffor(Size, SizeVertex: Integer;
FVF: DWORD; Pool: TBPOOL; Usage: TBUsage);
begin
glGenBuffersARB(1, @VBuffor);

glBindBufferARB(GL_ARRAY_BUFFER_ARB, VBuffor);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, Size * SizeVertex, nil,
BUsageToOGLUsage(Usage));

FSizeVertex := SizeVertex;
end;

destructor TBVertexBufforOGL.Destroy;
begin
UnInit();

inherited Destroy();
end;

function BUFFER_OFFSET(I: Cardinal): Pointer;
var
Ptr: Pointer absolute I;
begin
Result := Ptr;
end;

function TBVertexBufforOGL.Lock(Start, Count: DWORD): Pointer;
begin
Result := glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB);
end;

procedure TBVertexBufforOGL.Render(Typ: TBShapetype; Count: DWORD);
var
TheType: GLuint;
begin
glEnableClientState(GL_VERTEX_ARRAY);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, VBuffor);
case Typ of
BPOINTLIST: TheType := GL_POINTS;
BLINELIST: TheType := GL_LINES;
BLINESTRIP: TheType := GL_LINE_STRIP;
BTRIANGLELIST: TheType := GL_TRIANGLES;
BTRIANGLESTRIP: TheType := GL_TRIANGLE_STRIP;
BTRIANGLEFAN: TheType := GL_TRIANGLE_FAN;
end;
glDrawArrays(TheType, 0, Count);
glDisableClientState(GL_VERTEX_ARRAY);
end;

procedure TBVertexBufforOGL.UnInit;
begin
glDeleteBuffersARB(1, @VBuffor);
end;

procedure TBVertexBufforOGL.UnLock;
begin
glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
end;