Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm learning OpenGL 3.3 trying to do the following (as it is done in D3D)...

  • Create Texture of Width, Height, Pixel Format
  • Map texture memory
  • Loop write pixels
  • Unmap texture memory
  • Set Texture
  • Render

Right now though it renders as if the entire texture is black.

I can't find a reliable source for information on how to do this though. Almost every tutorial I've found just uses glTexSubImage2D and passes a pointer to memory.

Here is basically what my code does... (In this case it is generating an 1-byte Alpha Only texture but it is rendering it as the red channel for debugging)

GLuint pixelBufferID;
glGenBuffers(1, &pixelBufferID);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixelBufferID);
glBufferData(GL_PIXEL_UNPACK_BUFFER, 512 * 512 * 1, nullptr, GL_STREAM_DRAW);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);

GLuint textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, 512, 512, 0, GL_RED, GL_UNSIGNED_BYTE, nullptr);
glBindTexture(GL_TEXTURE_2D, 0);

glBindTexture(GL_TEXTURE_2D, textureID);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixelBufferID);
void *Memory = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
// Memory copied here, I know  this is valid because it is the same loop as in my working D3D version
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);

And then here is the render loop.

// This chunk left in for completeness
glUseProgram(glProgramId);
glBindVertexArray(glVertexArrayId);
glBindBuffer(GL_ARRAY_BUFFER, glVertexBufferId);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 20, 0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 20, 12);
GLuint transformLocationID = glGetUniformLocation(3, 'transform');
glUniformMatrix4fv(transformLocationID , 1, true, somematrix)

// Not sure if this is all I need to do
glBindTexture(GL_TEXTURE_2D, pTex->glTextureId);
GLuint textureLocationID = glGetUniformLocation(glProgramId, "texture");
glUniform1i(textureLocationID, 0);

glDrawArrays(GL_TRIANGLES, Offset*3, Triangles*3);

Vertex Shader

#version 330 core

in vec3 Position;
in vec2 TexCoords;
out vec2 TexOut;
uniform mat4 transform;

void main()
{
    TexOut = TexCoords;
    gl_Position = vec4(Position, 1.0) * transform;
}

Pixel Shader

#version 330 core

uniform sampler2D texture;
in vec2 TexCoords;
out vec4 fragColor;

void main()
{
   // Output color
   fragColor.r = texture2D(texture, TexCoords).r;
   fragColor.g = 0.0f;
   fragColor.b = 0.0f;
   fragColor.a = 1.0;
}
share|improve this question
    
If you just put the image data in an array and pass it to glTexImage2D, does the texture then show up? In other words, is the problem with initializing the texture, or with rendering it? –  Nathan Reed Sep 3 '12 at 21:59
    
@NathanReed, hmm it looks like the texture isn't showing up when using glTexImage2D. My bad, I guess I should have checked that. Now I just have to figure out why... –  NtscCobalt Sep 3 '12 at 22:54
    
@NathanReed, ok I got it working now. Looks like my original code needed to use the layout(location = 1) in the vertex shader for TexCoords and calls to glVertexAttribPointer. Also the out from the vertex shader must be named the same as the in in the pixel shader. –  NtscCobalt Sep 4 '12 at 0:07

2 Answers 2

up vote 3 down vote accepted

If you think about this conceptually, you'll see that all that mapping and filling a PBO does is map and fill a PBO - it does absolutely nothing to a texture object and you must handle that yourself in your own code.

The way to do this is via a glTexImage or glTexSubImage call, with the last (data) parameter handled in the same way as for other buffer object types; i.e. rather than being a pointer to system memory it is overloaded to function as an offset into the currently bound PBO.

So, to update a texture, you need to do the following:

glBindBuffer (GL_PIXEL_UNPACK_BUFFER, pboid);
byte *ptr = glMapBuffer (GL_PIXEL_UNPACK_BUFFER, ...);
// fill ptr here
glUnmapBuffer (GL_PIXEL_UNPACK_BUFFER);
// use while PBO is still bound, assumes GL_TEXTURE_2D and offset 0
glBindTexture (GL_TEXTURE_2D, textureid);
glTexSubImage2D (GL_TEXTURE_2D, ..., (void *) 0);
glBindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);

Regarding your specific use case, I suspect that this is not going to give you great performance. PBOs are really most useful where you can take advantage of the asynchronous nature of the transfer, i.e. by using the texture for drawing a frame or two after the texture is filled from the PBO. Since you're using the texture in the same frame you don't get that and OpenGL may need to stall until the transfer completes, as well as incurring the extra overhead of binding and mapping a PBO.

Using glMapBuffer itself is also likely to be a suboptimal path; see this link for a further discussion (it's somewhat out of date but I believe still relevant - especially since the advent of glMapBufferRange (see next point) I believe that glMapBuffer is not likely to be anything of a candidate for optimization or sensible implementation for driver writers). You will likely obtain a better result with glMapBufferRange if your driver supports it.

What I would do instead of all this however is just use stock glTexSubImage2D with a system memory pointer as source, and see how that performs. You may well find (particularly with a texture that's only 512X512X1) that it's more than fast enough for you. The worst case should be no worse than what I've just described above, your driver may very well have it's own optimal path for replacing the entire texture rect (it could double-buffer internally, for example), or you could double-buffer the texture yourself if needed. You shouldn't need to consider any alternate options unless this process proves to be a definite and measurable bottleneck.

share|improve this answer
    
Ah ok, this definitly helps clear things up. I originally thought that you allocated a PBO and then by binding the PBO and the Texture at the same time that it magically connected the two. Also thank you for the info about glMapBufferRange. PBOs are a hard topic to research through google. –  NtscCobalt Sep 3 '12 at 23:21

Pixel buffer objects are for performing pixel transfers to images. Pixel transfers are first and foremost copy operations.

You cannot map texture memory at all in OpenGL. You can use a buffer object as the destination for a copy operation (as in glGetTexImage). You can use a buffer object as the source for a copy operation (as in glTexSubImage2D). But you cannot map texture memory itself.

share|improve this answer
    
Ah ok, I think I understand a bit better now. Correct me if I'm wrong but GL_PIXEL_UNPACK_BUFFER acts as a GPU side buffer which can be used in conjunction with glTexImage2D to improve performance? –  NtscCobalt Sep 3 '12 at 22:58
    
@NtscCobalt: What mh01 said. –  Nicol Bolas Sep 3 '12 at 23:16
    
I would accepted your answer as well if possible but since I can only choose one I had to grab mh01's since he added a ton of details but thank you for your response. –  NtscCobalt Sep 4 '12 at 0:09

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.