www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Dynamic array and OpenGL problem

reply Mikko Ronkainen <mikoro iki.fi> writes:
Hello, Iäm playing around a little with OpenGL and I'm drawing trying to draw
raw pixels from memory to the screen. This is the function:

void glDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type,
const GLvoid *pixels);

Now I have a buffer with rgb data:

ubyte[3][1024][1280] framebuffer;

If I fill it and pass it to the opengl, everything works fine. But if I create
it dynamically:

ubyte[][][] framebuffer;
framebuffer = new ubyte[][][](3, height, width);

Now even after filling it I get some random garbage when rendering. Program
doesn't segfault though, so I assume memory is correctly allocated and written
- opengl just doesn't read it right. What am I doing wrong?
Jan 13 2008
next sibling parent reply Johan Granberg <lijat.meREM OVEgmail.com> writes:
Mikko Ronkainen wrote:

 Hello, Iäm playing around a little with OpenGL and I'm drawing trying to
 draw raw pixels from memory to the screen. This is the function:
 
 void glDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum
 type, const GLvoid *pixels);
 
 Now I have a buffer with rgb data:
 
 ubyte[3][1024][1280] framebuffer;

This creates a static array that is consecutive in memmory
 If I fill it and pass it to the opengl, everything works fine. But if I
 create it dynamically:
 
 ubyte[][][] framebuffer;
 framebuffer = new ubyte[][][](3, height, width);

This creates a dynamic array (of a dynamic arrays), dynamic arrays wont be consecutive in memory in the same way. A dynamic array is a pair of a size and a pointer so if you pass that to opengl which expects the array to be consecutive in memmory opengl will read the length part of the array as if it was part of the data and therfor producing garbage
 Now even after filling it I get some random garbage when rendering.
 Program doesn't segfault though, so I assume memory is correctly allocated
 and written - opengl just doesn't read it right. What am I doing wrong?

Jan 13 2008
parent reply Mikko Ronkainen <mikoro iki.fi> writes:
Johan Granberg Wrote:

 A dynamic array is a pair of a size and a pointer so if you pass that to
 opengl which expects the array to be consecutive in memmory opengl will
 read the length part of the array as if it was part of the data and therfor
 producing garbage

Ok, thanks. I'm out of ideas now - how should I solve the problem of variable size framebuffer then? I mean when you resize the window, I would like to resize the framebuffer accordingly. I'm now using that static array, and I cannot see any method to resize it. Or alternatively having some sort of conversion before sending dynamic array to opengl?
Jan 13 2008
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Mikko Ronkainen wrote:
 Johan Granberg Wrote:
 
 A dynamic array is a pair of a size and a pointer so if you pass that to
 opengl which expects the array to be consecutive in memmory opengl will
 read the length part of the array as if it was part of the data and therfor
 producing garbage

Ok, thanks. I'm out of ideas now - how should I solve the problem of variable size framebuffer then? I mean when you resize the window, I would like to resize the framebuffer accordingly. I'm now using that static array, and I cannot see any method to resize it. Or alternatively having some sort of conversion before sending dynamic array to opengl?

Just make a 1D array and compute the size yourself. ubyte[] framebuffer = new ubyte[3*width*height]; Then pass framebuffer.ptr to the OpenGL call. --bb
Jan 13 2008
parent Mikko Ronkainen <mikoro iki.fi> writes:
Bill Baxter Wrote:

 Just make a 1D array and compute the size yourself.
 
 ubyte[] framebuffer = new ubyte[3*width*height];
 

Thanks! That didn't come to my mind :) Now it works very well.
Jan 13 2008
prev sibling next sibling parent reply Mikko Ronkainen <mikoro iki.fi> writes:
Now when I got it working I'm thinking about speeding things up a bit. Few
questions:

ubyte[] getFramebuffer() { return framebuffer; }

Does D pass it around as a reference?

And now I'm zeroing the framebuffer like this:

for(int i=0; i<(width*height*3); ++i)
    framebuffer[i] = 0;

Is there more speedier way to just zero the memory? This takes most of the time
in the rendering loop...

Thanks!
Jan 14 2008
parent reply Matti Niemenmaa <see_signature for.real.address> writes:
Mikko Ronkainen wrote:
 Now when I got it working I'm thinking about speeding things up a bit. Few
questions:
 
 ubyte[] getFramebuffer() { return framebuffer; }
 
 Does D pass it around as a reference?

Yes. ubyte[] is essentially: struct ubyte_array { size_t length; ubyte* ptr; } And that's what gets passed around, so 8 bytes of data on a 32-bit system, regardless of the size of the array.
 And now I'm zeroing the framebuffer like this:
 
 for(int i=0; i<(width*height*3); ++i)
     framebuffer[i] = 0;
 
 Is there more speedier way to just zero the memory? This takes most of the
time in the rendering loop...

There's: framebuffer[] = 0; But I don't know if it's faster. Theoretically it should use memset, but if it doesn't, you can do it manually: import std.c.string; // or if using Tango, import tango.stdc.string; ... // going from memory here, check the docs to be sure of the parameter order memset(framebuffer.ptr, 0, framebuffer.length); -- E-mail address: matti.niemenmaa+news, domain is iki (DOT) fi
Jan 14 2008
parent Mikko Ronkainen <mikoro iki.fi> writes:
Matti Niemenmaa Wrote:

 There's:
 
 framebuffer[] = 0;
 
 But I don't know if it's faster. Theoretically it should use memset, but if it 
 doesn't, you can do it manually:

Thanks Matti, the performance increase was about 90% using that method :)
Jan 14 2008
prev sibling parent reply Mikko Ronkainen <mikoro iki.fi> writes:
Ok, I'm still trying to optimize the code a little. I'm trying to code my own
little
software 3D "engine" and here's a snippet from the triangle scan conversion:

int leftOffset = (y * framebufferWidth + cast(int)(leftX + 0.5)) * 3;
int rightOffset = (y * framebufferWidth + cast(int)(rightX + 0.5)) * 3;

for(int i=leftOffset; i<=rightOffset; i+=3)
{
    framebuffer[i] = color.r;
    framebuffer[i + 1] = color.g;
    framebuffer[i + 2] = color.b;
}

It draws one scan line from a triangle (setting all pixels on a line from
leftOffset to
rightOffset to given color). Now it seems that in C you can go about it
something like
this (pseudo code):

memset(framebuffer+left, color, (right-left+1));

This assumes color is an int so framebuffer format is RGBA. Now I did a test in
D like
this:

ubyte[] framebuffer = window.getFramebuffer();
memset(framebuffer.ptr, 0xffff, 1);

I thought I would get a white and a red pixel (framebuffer format is RGB), but
just got
one red pixel. I get one white, if I change last parameter to 3, so it seems
memset in this case only writes bytes. My question is: what is the fastest way
to set continuous block of bytes to some repeating sequence (int this case
rgb[a] values)?
Jan 15 2008
parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Mikko Ronkainen" <mikoro iki.fi> wrote in message 
news:fmi0gi$2b99$1 digitalmars.com...
 Ok, I'm still trying to optimize the code a little. I'm trying to code my 
 own little
 software 3D "engine" and here's a snippet from the triangle scan 
 conversion:

 int leftOffset = (y * framebufferWidth + cast(int)(leftX + 0.5)) * 3;
 int rightOffset = (y * framebufferWidth + cast(int)(rightX + 0.5)) * 3;

 for(int i=leftOffset; i<=rightOffset; i+=3)
 {
    framebuffer[i] = color.r;
    framebuffer[i + 1] = color.g;
    framebuffer[i + 2] = color.b;
 }

 It draws one scan line from a triangle (setting all pixels on a line from 
 leftOffset to
 rightOffset to given color). Now it seems that in C you can go about it 
 something like
 this (pseudo code):

 memset(framebuffer+left, color, (right-left+1));

 This assumes color is an int so framebuffer format is RGBA. Now I did a 
 test in D like
 this:

 ubyte[] framebuffer = window.getFramebuffer();
 memset(framebuffer.ptr, 0xffff, 1);

 I thought I would get a white and a red pixel (framebuffer format is RGB), 
 but just got
 one red pixel. I get one white, if I change last parameter to 3, so it 
 seems memset in this case only writes bytes. My question is: what is the 
 fastest way to set continuous block of bytes to some repeating sequence 
 (int this case rgb[a] values)?

So I assume your 'color' is a struct defined something like struct Color { int r, g, b; } How about something like.. (cast(Color[])frameBuffer[leftOffset .. rightOffset + 1])[] = color; First we're slicing the array to get only the subset that we want. The upper bound is noninclusive so we have to put +1 to include the byte at rightOffset. Then we cast it to a Color[] -- this will perform a runtime check to ensure that the size of the data in the source array really is a multiple of Color.sizeof. Lastly we just slice-fill as before. You might want/need to make Color "packed" to ensure that the compiler doesn't insert any extra padding in for alignment: align(1) struct Color { int r, g, b; }
Jan 15 2008