Commit bbdd6d5c authored by Tim Übelhör's avatar Tim Übelhör

Reading from textures

parent 5f2ef2d9
......@@ -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");
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment