143 lines
3.5 KiB
C++
143 lines
3.5 KiB
C++
#include "Bgra8ReadbackPipeline.h"
|
|
|
|
#include "../frames/SystemFrameTypes.h"
|
|
|
|
#include <cstring>
|
|
|
|
Bgra8ReadbackPipeline::~Bgra8ReadbackPipeline()
|
|
{
|
|
Shutdown();
|
|
}
|
|
|
|
bool Bgra8ReadbackPipeline::Initialize(unsigned width, unsigned height, std::size_t pboDepth)
|
|
{
|
|
Shutdown();
|
|
|
|
mWidth = width;
|
|
mHeight = height;
|
|
mRowBytes = VideoIORowBytes(VideoIOPixelFormat::Bgra8, width);
|
|
if (mWidth == 0 || mHeight == 0 || mRowBytes == 0)
|
|
return false;
|
|
|
|
if (!CreateRenderTarget())
|
|
{
|
|
Shutdown();
|
|
return false;
|
|
}
|
|
|
|
const std::size_t byteCount = static_cast<std::size_t>(mRowBytes) * static_cast<std::size_t>(mHeight);
|
|
if (!mPboRing.Initialize(pboDepth, byteCount))
|
|
{
|
|
Shutdown();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void Bgra8ReadbackPipeline::Shutdown()
|
|
{
|
|
mPboRing.Shutdown();
|
|
DestroyRenderTarget();
|
|
mWidth = 0;
|
|
mHeight = 0;
|
|
mRowBytes = 0;
|
|
}
|
|
|
|
bool Bgra8ReadbackPipeline::RenderAndQueue(uint64_t frameIndex, const RenderCallback& renderFrame)
|
|
{
|
|
if (mFramebuffer == 0 || !renderFrame)
|
|
return false;
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
|
|
renderFrame(frameIndex);
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
|
|
return mPboRing.QueueReadback(mFramebuffer, mWidth, mHeight, frameIndex);
|
|
}
|
|
|
|
void Bgra8ReadbackPipeline::ConsumeCompleted(
|
|
const AcquireFrameCallback& acquireFrame,
|
|
const PublishFrameCallback& publishFrame,
|
|
const CounterCallback& onAcquireMiss,
|
|
const CounterCallback& onCompleted)
|
|
{
|
|
if (!acquireFrame || !publishFrame)
|
|
return;
|
|
|
|
PboReadbackRing::CompletedReadback readback;
|
|
while (mPboRing.TryAcquireCompleted(readback))
|
|
{
|
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, readback.pbo);
|
|
void* mapped = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
|
|
if (!mapped)
|
|
{
|
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
|
mPboRing.ReleaseCompleted(readback);
|
|
continue;
|
|
}
|
|
|
|
SystemFrame frame;
|
|
if (acquireFrame(frame))
|
|
{
|
|
const std::size_t byteCount = static_cast<std::size_t>(frame.rowBytes) * static_cast<std::size_t>(frame.height);
|
|
if (frame.bytes != nullptr && byteCount <= readback.byteCount)
|
|
{
|
|
std::memcpy(frame.bytes, mapped, byteCount);
|
|
frame.frameIndex = readback.frameIndex;
|
|
frame.pixelFormat = VideoIOPixelFormat::Bgra8;
|
|
publishFrame(frame);
|
|
if (onCompleted)
|
|
onCompleted();
|
|
}
|
|
}
|
|
else if (onAcquireMiss)
|
|
{
|
|
onAcquireMiss();
|
|
}
|
|
|
|
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
|
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
|
mPboRing.ReleaseCompleted(readback);
|
|
}
|
|
}
|
|
|
|
bool Bgra8ReadbackPipeline::CreateRenderTarget()
|
|
{
|
|
glGenFramebuffers(1, &mFramebuffer);
|
|
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
|
|
|
|
glGenTextures(1, &mTexture);
|
|
glBindTexture(GL_TEXTURE_2D, mTexture);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
glTexImage2D(
|
|
GL_TEXTURE_2D,
|
|
0,
|
|
GL_RGBA8,
|
|
static_cast<GLsizei>(mWidth),
|
|
static_cast<GLsizei>(mHeight),
|
|
0,
|
|
GL_BGRA,
|
|
GL_UNSIGNED_INT_8_8_8_8_REV,
|
|
nullptr);
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture, 0);
|
|
|
|
const bool complete = glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
return complete;
|
|
}
|
|
|
|
void Bgra8ReadbackPipeline::DestroyRenderTarget()
|
|
{
|
|
if (mFramebuffer != 0)
|
|
glDeleteFramebuffers(1, &mFramebuffer);
|
|
if (mTexture != 0)
|
|
glDeleteTextures(1, &mTexture);
|
|
mFramebuffer = 0;
|
|
mTexture = 0;
|
|
}
|