Skip to content
Snippets Groups Projects
Commit bbdd6d5c authored by Tim Übelhör's avatar Tim Übelhör
Browse files

Reading from textures

parent 5f2ef2d9
Branches
Tags v0.5
No related merge requests found
......@@ -28,6 +28,7 @@ add_library(scigl_render
src/buffer/frame_buffer.cpp
src/buffer/frame_buffer_reader.cpp
src/buffer/texture2d.cpp
src/buffer/texture_reader.cpp
src/render/depth_simulator.cpp
src/render/onscreen_render.cpp
src/render/rasterizer.cpp
......
......@@ -28,6 +28,15 @@ public:
/** unbinds this texture */
void unbind() const;
/**
* Reads the texture in the pixels pointer.
* Note: If a non-zero named buffer object is bound to the
* GL_PIXEL_PACK_BUFFER target (see glBindBuffer) while a texture image is
* specified, pixels is treated as a byte offset into the buffer object's
* data store.
*/
void read_image(GLvoid *pixels);
/** upload an image to the texture. */
void store_image(const GLvoid *image) const;
......
#pragma once
#include <scigl_render/buffer/texture2d.hpp>
#include <array>
#include <functional>
#include <memory>
namespace scigl_render
{
/*!
Transfer data from a texture to the CPU.
Two pixel buffer objects are used like a double buffer: one PBO is filled
asynchronously with data from the frame buffer while the other one is ready to
be mapped to the clients memory. Consequently the results of a rendering is
delayed by one read call.
*/
class TextureReader
{
public:
/*!
Renders the scene off-screen and calculates the depth values.
\param buffer read from this texture
\param pixel_size the size of each pixel: number_channels * sizeof(type)
*/
TextureReader(std::shared_ptr<Texture2D> buffer,
size_t pixel_size);
/*!
Starts reading from the FBO to the backbuffer PBO. This operation is
asynchronous.
*/
void start_read() const;
/*!
Reads synchronously from the frontbuffer PBO. Operate on this data while
another read is running on the backbuffer :)
\retuns might return NULL otherwise the data
*/
void *do_read() const;
/*!
Unmaps the OpenGL memory.
*/
void end_read() const;
/*! Swap the front- and backbuffer */
void swap_buffers();
private:
std::shared_ptr<Texture2D> texture;
// Two pbos one to read to the other one to map form, alternating
std::array<GLuint, 2> pbos;
// transfer from fbo to pbo via glReadPixels
int backbuffer_index = 0;
// transfer from pbo to CPU memory
int frontbuffer_index = 1;
};
} // namespace scigl_render
......@@ -2,7 +2,7 @@
#include <scigl_render/gl_context.hpp>
#include <scigl_render/render/depth_simulator.hpp>
#include <scigl_render/buffer/frame_buffer.hpp>
#include <scigl_render/buffer/frame_buffer_reader.hpp>
#include <scigl_render/buffer/texture_reader.hpp>
#include <scigl_render/render/rasterizer.hpp>
#include <scigl_render/render/texture_fullscreen_render.hpp>
#include <memory>
......@@ -44,7 +44,7 @@ private:
// render to fbo
std::shared_ptr<Texture2D> fbo_texture;
std::shared_ptr<FrameBuffer> framebuffer;
std::unique_ptr<FramebufferReader> fbo_reader;
std::unique_ptr<TextureReader> tex_reader;
// display fullscreen quad from other texture (to showcase the mapping)
TextureFullscreenRender texture_render;
std::shared_ptr<Texture2D> quad_texture;
......
......@@ -65,6 +65,13 @@ void Texture2D::unbind() const
glBindTexture(GL_TEXTURE_2D, 0);
}
void Texture2D::read_image(GLvoid *pixels)
{
bind();
glGetTexImage(GL_TEXTURE_2D, 0, format, type, pixels);
unbind();
}
void Texture2D::store_image(const GLvoid *image) const
{
bind();
......
#include <algorithm>
#include <scigl_render/check_gl_error.hpp>
#include <scigl_render/buffer/texture_reader.hpp>
#include <stdexcept>
namespace scigl_render
{
TextureReader::TextureReader(std::shared_ptr<Texture2D> buffer,
size_t pixel_size)
: texture(buffer)
{
glGenBuffers(pbos.size(), pbos.data());
size_t buffer_size = texture->get_width() *
texture->get_height() *
pixel_size;
for (size_t i = 0; i < pbos.size(); i++)
{
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbos[i]);
// constantly reading new contents
glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, 0,
GL_DYNAMIC_READ);
}
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
check_gl_error("framebuffer-reader created pbos");
}
void TextureReader::start_read() const
{
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbos[backbuffer_index]);
texture->read_image(0);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
}
void *TextureReader::do_read() const
{
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbos[frontbuffer_index]);
return glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
}
void TextureReader::end_read() const
{
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
}
void TextureReader::swap_buffers()
{
std::swap(backbuffer_index, frontbuffer_index);
}
} // namespace scigl_render
......@@ -15,8 +15,7 @@ DepthOffscreenRender::DepthOffscreenRender(std::shared_ptr<GLContext> context,
fbo_texture(texture)
{
framebuffer = std::make_shared<FrameBuffer>(fbo_texture);
fbo_reader = std::unique_ptr<FramebufferReader>(
new FramebufferReader(framebuffer, pixel_size));
tex_reader.reset(new TextureReader(fbo_texture, pixel_size));
// create second texture to copy the data to
quad_texture = std::make_shared<Texture2D>(
fbo_texture->get_width(), fbo_texture->get_height(),
......@@ -48,16 +47,16 @@ void DepthOffscreenRender::next_frame(
rasterizer.activate_all();
framebuffer->deactivate();
// read data from fbo
fbo_reader->start_read();
// read data from texture
tex_reader->start_read();
check_gl_error("asynchronous reading to pbo");
auto data = fbo_reader->do_read();
auto data = tex_reader->do_read();
check_gl_error("synchronous reading from pbo");
// display the data on screen
display_data(data);
fbo_reader->end_read();
fbo_reader->swap_buffers();
tex_reader->end_read();
tex_reader->swap_buffers();
check_gl_error("end synchronous reading");
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment