Thread overview
Dynamic array and OpenGL problem
Jan 13, 2008
Mikko Ronkainen
Jan 13, 2008
Johan Granberg
Jan 13, 2008
Mikko Ronkainen
Jan 13, 2008
Bill Baxter
Jan 13, 2008
Mikko Ronkainen
Jan 14, 2008
Mikko Ronkainen
Jan 14, 2008
Matti Niemenmaa
Jan 14, 2008
Mikko Ronkainen
Jan 15, 2008
Mikko Ronkainen
January 13, 2008
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?
January 13, 2008
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?

January 13, 2008
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?
January 13, 2008
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
January 13, 2008
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.
January 14, 2008
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!
January 14, 2008
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
January 14, 2008
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 :)
January 15, 2008
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)?

January 15, 2008
"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; }