glMapBuffer() doesn’t return nullptr, but why it doesn’t work?
struct ImageMappedResource {
uint8_t *_rgba_data;
size_t _rowPitch;
glm::ivec3 _extent;
void setTexel(const glm::ivec2 &pt, uint32_t color);
uint32_t getTexel(const glm::ivec2 &pt);
void drawRect(const glm::ivec2 &a, const glm::ivec2 &b, uint32_t color);
};
ImageMappedResource _Image::map() {
// Referenced from [Map and fill texture using PBO (OpenGL 3.3)](https://gamedev.stackexchange.com/questions/35486/map-and-fill-texture-using-pbo-opengl-3-3)
ImageMappedResource mappedResource = {};
DEBUG_VERIFY(_extent.z == 1); // Make sure not 3D
glGenBuffers(1, &this->_gl._pboID);
glBindTexture(GL_TEXTURE_2D, this->_gl.tex);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->_gl._pboID);
glBufferData(GL_PIXEL_UNPACK_BUFFER, (_extent.x * _extent.y * 4), nullptr, GL_STREAM_DRAW); // Allocate memory for PBO
mappedResource._rgba_data = (uint8_t *)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_WRITE);
gl_checkErrors("glMapBuffer");
mappedResource._rowPitch = (4*_extent.x);
mappedResource._extent = _extent;
return mappedResource;
}
void _Image::unmap() {
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); // Unmap
glBindTexture(GL_TEXTURE_2D, 0); // Unbind
glDeleteBuffers(1, &this->_gl._pboID); // Delete PBO
}
Let me explain it doesn’t work like how? Let ‘image’ an image from file, so I want to draw a rectangle from (0, 0) to (20, 20), but the image is not modified, I mean it’s impossible to modify the memory, but why?
ImageMappedResource mappedResource = image->map();
mappedResource.drawRect(glm::ivec2(0, 0), glm::ivec2(20, 20), 0xFF00FF00);
image->unmap();
You’re missing a glTexImage
/glTexSubImage
call.
Binding a buffer to GL_PIXEL_UNPACK_BUFFER
simply causes those calls to read from the buffer rather than from client memory (and avoids synchronisation).
What do you mean with missing glTexImage/glTexSubImage call? Where should I place it? According to my understand, if I update the unmap() function then should it look like this but this makes the program crashes with an error: OpenGL error in “useProgram”: 1282 (GL_INVALID_OPERATION)
void _Image::unmap() {
// Update texture with new data (Where glTexImage2D should be placed?).
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGBA,
_extent.x,
_extent.y,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
nullptr // Should I use mappedResource._rgba_data instead of nullptr?
);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); // Unmap
glBindTexture(GL_TEXTURE_2D, 0); // Unbind
glDeleteBuffers(1, &this->_gl._pboID); // Delete PBO
}
You need to unmap the buffer before calling glTexImage2D
:
In general, buffers have to be unmapped when accessed by OpenGL commands (i.e. the buffer can be accessible from the client or from the implementation, but not both at once). This restriction doesn’t apply to persistently-mapped buffers (GL_MAP_PERSISTENT_BIT
set both in glBufferStorage
and glMapBufferRange
), but those require OpenGL 4.4 or the ARB_buffer_storage
extension.
1 Like
@GClements > Thank you, unmap() is fixed now, which means that if there is a modification between map() and unmap() then the texture will be updated.
But, why when I call map() then the image is cleared which means it becomes empty? If there is no modification between map() and unmap() then the image should stay the same instead of becoming empty. How to fix it?
ImageMappedResource _Image::map() {
// Referenced from [Map and fill texture using PBO (OpenGL 3.3)](https://gamedev.stackexchange.com/questions/35486/map-and-fill-texture-using-pbo-opengl-3-3)
ImageMappedResource mappedResource = {};
DEBUG_VERIFY(_extent.z == 1); // Make sure not 3D
glGenBuffers(1, &this->_gl._pboID);
glBindTexture(GL_TEXTURE_2D, this->_gl.tex);
// TODO: Keep the previous image of that texture above.
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->_gl._pboID);
glBufferData(GL_PIXEL_UNPACK_BUFFER, (_extent.x * _extent.y * 4), nullptr, GL_STREAM_DRAW); // Allocate memory for PBO
mappedResource._rgba_data = (uint8_t *)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_WRITE);
gl_checkErrors("glMapBuffer");
mappedResource._rowPitch = (4*_extent.x);
mappedResource._extent = _extent;
return mappedResource;
}
void _Image::unmap() {
// Unmap
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
// Update texture with new data
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _extent.x, _extent.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glBindTexture(GL_TEXTURE_2D, 0); // Unbind
glDeleteBuffers(1, &this->_gl._pboID); // Delete PBO
}
That’s what you told it to do. You allocated a new buffer of storage (that’s what glBufferData
does) in map
. Then you uploaded whatever is in that new buffer into the image in unmap
.
Remember: you are not “mapping the texture”. You are mapping a buffer from which you later transfer pixel data to the texture. So its up to you to properly manage the contents of that buffer’s storage.
1 Like
Thank you, so I need to big modify the function map() in order to do what I want, it will need a lot of skill, maybe in the future. I realize that the goal of map / unmap is for advanced feature such as texture painting or dynamically update voxel texture with CPU, etc. But now, I use a basic method such as when I want to update a texture, I delete it and create a new texture with new data, it’s still ok because no big performance is required.