format: reformatting files

This commit is contained in:
2026-07-13 15:30:43 +08:00
parent 7522543c48
commit e5eeaddf2f
511 changed files with 274803 additions and 207140 deletions
+55 -55
View File
@@ -21,62 +21,62 @@ add_subdirectory(ocioconf)
add_subdirectory(opengl)
add_subdirectory(plugin)
set(OLIVE_SOURCES
${OLIVE_SOURCES}
render/audioplaybackcache.cpp
render/audioplaybackcache.h
render/audiowaveformcache.cpp
render/audiowaveformcache.h
render/backend/dynamicrenderer.cpp
render/backend/dynamicrenderer.h
render/backend/renderbackend_c.h
render/cancelatom.h
render/colormanagement.cpp
render/colorprocessor.cpp
render/colorprocessor.h
render/colorprocessorcache.h
render/diskmanager.cpp
render/diskmanager.h
render/framehashcache.cpp
render/framehashcache.h
render/framemanager.cpp
render/framemanager.h
render/interlacetexture.cpp
render/loopmode.h
render/managedcolor.cpp
render/managedcolor.h
render/playbackcache.cpp
render/playbackcache.h
render/previewaudiodevice.cpp
render/previewaudiodevice.h
render/previewautocacher.cpp
render/previewautocacher.h
render/projectcopier.cpp
render/projectcopier.h
render/renderer.cpp
render/renderer.h
render/rendercache.h
render/renderjobtracker.cpp
render/renderjobtracker.h
render/rendermanager.cpp
render/rendermanager.h
render/renderworkerpool.cpp
render/renderworkerpool.h
render/rendermodes.h
render/renderprocessor.cpp
render/renderprocessor.h
render/renderticket.cpp
render/renderticket.h
render/shadercode.h
render/subtitleparams.cpp
render/subtitleparams.h
render/texture.cpp
render/texture.h
render/videoparams.cpp
render/videoparams.h
PARENT_SCOPE
${OLIVE_SOURCES}
render/audioplaybackcache.cpp
render/audioplaybackcache.h
render/audiowaveformcache.cpp
render/audiowaveformcache.h
render/backend/dynamicrenderer.cpp
render/backend/dynamicrenderer.h
render/backend/renderbackend_c.h
render/cancelatom.h
render/colormanagement.cpp
render/colorprocessor.cpp
render/colorprocessor.h
render/colorprocessorcache.h
render/diskmanager.cpp
render/diskmanager.h
render/framehashcache.cpp
render/framehashcache.h
render/framemanager.cpp
render/framemanager.h
render/interlacetexture.cpp
render/loopmode.h
render/managedcolor.cpp
render/managedcolor.h
render/playbackcache.cpp
render/playbackcache.h
render/previewaudiodevice.cpp
render/previewaudiodevice.h
render/previewautocacher.cpp
render/previewautocacher.h
render/projectcopier.cpp
render/projectcopier.h
render/renderer.cpp
render/renderer.h
render/rendercache.h
render/renderjobtracker.cpp
render/renderjobtracker.h
render/rendermanager.cpp
render/rendermanager.h
render/renderworkerpool.cpp
render/renderworkerpool.h
render/rendermodes.h
render/renderprocessor.cpp
render/renderprocessor.h
render/renderticket.cpp
render/renderticket.h
render/shadercode.h
render/subtitleparams.cpp
render/subtitleparams.h
render/texture.cpp
render/texture.h
render/videoparams.cpp
render/videoparams.h
PARENT_SCOPE
)
set(OLIVE_RESOURCES
${OLIVE_RESOURCES}
PARENT_SCOPE
${OLIVE_RESOURCES}
PARENT_SCOPE
)
+29 -24
View File
@@ -37,21 +37,24 @@ DynamicRenderer::~DynamicRenderer()
// system libGL/libvulkan loader is never mistaken for an Oak render backend.
QString DynamicRenderer::LibraryFilename() const
{
const QString base = backend_ == QStringLiteral("vulkan")
? QStringLiteral("oakvulkan")
: QStringLiteral("oakgl");
const QString base = backend_ == QStringLiteral("vulkan") ?
QStringLiteral("oakvulkan") :
QStringLiteral("oakgl");
#if defined(Q_OS_WIN)
const QString filename = base + QStringLiteral(".dll");
#elif defined(Q_OS_MAC)
const QString filename = QStringLiteral("lib") + base + QStringLiteral(".dylib");
const QString filename =
QStringLiteral("lib") + base + QStringLiteral(".dylib");
#else
const QString filename = QStringLiteral("lib") + base + QStringLiteral(".so");
const QString filename =
QStringLiteral("lib") + base + QStringLiteral(".so");
#endif
const QDir app_dir(QCoreApplication::applicationDirPath());
const QStringList candidates = {
app_dir.filePath(filename),
app_dir.filePath(QDir(QStringLiteral("render_backends")).filePath(filename)),
app_dir.filePath(
QDir(QStringLiteral("render_backends")).filePath(filename)),
app_dir.filePath(QDir(QStringLiteral("../lib")).filePath(filename)),
app_dir.filePath(QDir(QStringLiteral("../../lib")).filePath(filename)),
app_dir.filePath(QDir(QStringLiteral("../app")).filePath(filename)),
@@ -77,9 +80,9 @@ bool DynamicRenderer::Load()
library_.setFileName(LibraryFilename());
if (!library_.load()) {
if (backend_ == QStringLiteral("vulkan")) {
qWarning() << "Failed to load Vulkan render backend"
<< library_.fileName() << library_.errorString()
<< "falling back to OpenGL backend";
qWarning()
<< "Failed to load Vulkan render backend" << library_.fileName()
<< library_.errorString() << "falling back to OpenGL backend";
backend_ = QStringLiteral("opengl");
library_.setFileName(LibraryFilename());
}
@@ -126,9 +129,10 @@ bool DynamicRenderer::Load()
bool DynamicRenderer::ResolveFunctions()
{
ResetFunctions();
#define RESOLVE(member, type, symbol) \
#define RESOLVE(member, type, symbol) \
member = reinterpret_cast<type>(library_.resolve(symbol)); \
if (!member) return false
if (!member) \
return false
RESOLVE(create_, OakBackendCreateFn, "oak_renderer_create");
RESOLVE(destroy_, OakBackendDestroyFn, "oak_renderer_destroy");
@@ -259,7 +263,7 @@ void DynamicRenderer::PostInit()
// Forwards render target clearing through the C ABI.
void DynamicRenderer::ClearDestination(Texture *texture, double r, double g,
double b, double a)
double b, double a)
{
clear_destination_(handle_, texture, r, g, b, a);
}
@@ -281,16 +285,16 @@ void DynamicRenderer::DestroyNativeShader(QVariant shader)
// Uploads CPU pixel data into a backend texture through the dynamic ABI.
void DynamicRenderer::UploadToTexture(const QVariant &handle,
const VideoParams &params, const void *data,
int linesize)
const VideoParams &params,
const void *data, int linesize)
{
upload_to_texture_(handle_, &handle, &params, data, linesize);
}
// Downloads backend texture data into a caller-provided CPU buffer.
void DynamicRenderer::DownloadFromTexture(const QVariant &handle,
const VideoParams &params, void *data,
int linesize)
const VideoParams &params, void *data,
int linesize)
{
download_from_texture_(handle_, &handle, &params, data, linesize);
}
@@ -313,9 +317,9 @@ Color DynamicRenderer::GetPixelFromTexture(Texture *texture, const QPointF &pt)
// null so callers can avoid GL-only paths.
QOpenGLContext *DynamicRenderer::OpenGLContext() const
{
return opengl_context_ && handle_
? static_cast<QOpenGLContext *>(opengl_context_(handle_))
: nullptr;
return opengl_context_ && handle_ ?
static_cast<QOpenGLContext *>(opengl_context_(handle_)) :
nullptr;
}
// Reports the effective backend after any load-time fallback has completed.
@@ -331,8 +335,8 @@ bool DynamicRenderer::IsVulkan() const
// Dispatches a shader blit to the loaded backend.
void DynamicRenderer::Blit(QVariant shader, AcceleratedJob &job,
Texture *destination, VideoParams destination_params,
bool clear_destination)
Texture *destination, VideoParams destination_params,
bool clear_destination)
{
blit_(handle_, &shader, &job, destination, &destination_params,
clear_destination);
@@ -340,12 +344,13 @@ void DynamicRenderer::Blit(QVariant shader, AcceleratedJob &job,
// Allocates a backend-native texture and wraps its opaque handle in QVariant.
QVariant DynamicRenderer::CreateNativeTexture(int width, int height, int depth,
PixelFormat format, int channel_count,
const void *data, int linesize)
PixelFormat format,
int channel_count,
const void *data, int linesize)
{
QVariant out;
create_native_texture_(handle_, width, height, depth, format, channel_count,
data, linesize, &out);
data, linesize, &out);
return out;
}
+13 -13
View File
@@ -42,26 +42,26 @@ public:
// Runs backend post-init setup.
virtual void PostInit() override;
// Clears either a native texture destination or the backend output target.
virtual void ClearDestination(Texture *texture = nullptr,
double r = 0.0, double g = 0.0,
double b = 0.0, double a = 0.0) override;
virtual void ClearDestination(Texture *texture = nullptr, double r = 0.0,
double g = 0.0, double b = 0.0,
double a = 0.0) override;
// Creates a native shader through the dynamic backend.
virtual QVariant CreateNativeShader(ShaderCode code) override;
// Destroys a native shader through the dynamic backend.
virtual void DestroyNativeShader(QVariant shader) override;
// Uploads CPU pixels to a backend texture.
virtual void UploadToTexture(const QVariant &handle,
const VideoParams &params, const void *data,
int linesize) override;
const VideoParams &params, const void *data,
int linesize) override;
// Downloads backend texture pixels to CPU memory.
virtual void DownloadFromTexture(const QVariant &handle,
const VideoParams &params, void *data,
int linesize) override;
const VideoParams &params, void *data,
int linesize) override;
// Waits for backend work to complete.
virtual void Flush() override;
// Reads one pixel from a backend texture.
virtual Color GetPixelFromTexture(Texture *texture,
const QPointF &pt) override;
const QPointF &pt) override;
// Returns the wrapped OpenGL context for OpenGL backends.
virtual QOpenGLContext *OpenGLContext() const override;
@@ -79,13 +79,13 @@ public:
protected:
// Dispatches a shader blit through the dynamic backend.
virtual void Blit(QVariant shader, AcceleratedJob &job,
Texture *destination, VideoParams destination_params,
bool clear_destination) override;
Texture *destination, VideoParams destination_params,
bool clear_destination) override;
// Allocates a native texture through the dynamic backend.
virtual QVariant CreateNativeTexture(int width, int height, int depth,
PixelFormat format, int channel_count,
const void *data = nullptr,
int linesize = 0) override;
PixelFormat format, int channel_count,
const void *data = nullptr,
int linesize = 0) override;
// Releases a native texture through the dynamic backend.
virtual void DestroyNativeTexture(QVariant texture) override;
// Releases backend-owned renderer resources.
+23 -23
View File
@@ -7,7 +7,8 @@
#ifdef _WIN32
#define OAK_RENDER_BACKEND_EXPORT extern "C" __declspec(dllexport)
#else
#define OAK_RENDER_BACKEND_EXPORT extern "C" __attribute__((visibility("default")))
#define OAK_RENDER_BACKEND_EXPORT \
extern "C" __attribute__((visibility("default")))
#endif
#ifdef __cplusplus
@@ -50,14 +51,14 @@ typedef OakRenderBackendHandle (*OakBackendCreateFn)(void *parent);
typedef void (*OakBackendDestroyFn)(OakRenderBackendHandle handle);
/* Queries backend metadata and capability bits. */
typedef bool (*OakBackendGetInfoFn)(OakRenderBackendHandle handle,
struct OakRenderBackendInfo *out_info);
struct OakRenderBackendInfo *out_info);
/* Checks whether the backend can run on the current machine. */
typedef bool (*OakBackendIsAvailableFn)(OakRenderBackendHandle handle);
/* Initializes backend-owned device/context resources. */
typedef bool (*OakBackendInitFn)(OakRenderBackendHandle handle);
/* Initializes the backend against a caller-supplied GL context when applicable. */
typedef void (*OakBackendInitWithContextFn)(OakRenderBackendHandle handle,
void *context);
void *context);
/* Runs backend post-initialization after the device/context exists. */
typedef void (*OakBackendPostInitFn)(OakRenderBackendHandle handle);
/* Runs backend post-destroy cleanup before the library unloads. */
@@ -66,40 +67,39 @@ typedef void (*OakBackendPostDestroyFn)(OakRenderBackendHandle handle);
typedef void (*OakBackendDestroyInternalFn)(OakRenderBackendHandle handle);
/* Clears a texture destination or implicit output target. */
typedef void (*OakBackendClearDestinationFn)(OakRenderBackendHandle handle,
void *texture, double r, double g,
double b, double a);
void *texture, double r, double g,
double b, double a);
/* Creates a native texture and writes a QVariant-compatible handle. */
typedef void (*OakBackendCreateNativeTextureFn)(OakRenderBackendHandle handle,
int width, int height, int depth,
int format, int channel_count,
const void *data, int linesize,
void *out_variant);
typedef void (*OakBackendCreateNativeTextureFn)(
OakRenderBackendHandle handle, int width, int height, int depth, int format,
int channel_count, const void *data, int linesize, void *out_variant);
/* Destroys a native texture represented by a QVariant-compatible handle. */
typedef void (*OakBackendDestroyNativeTextureFn)(OakRenderBackendHandle handle,
const void *variant);
const void *variant);
/* Creates a native shader and writes a QVariant-compatible handle. */
typedef void (*OakBackendCreateNativeShaderFn)(OakRenderBackendHandle handle,
const void *shader_code,
void *out_variant);
const void *shader_code,
void *out_variant);
/* Destroys a native shader represented by a QVariant-compatible handle. */
typedef void (*OakBackendDestroyNativeShaderFn)(OakRenderBackendHandle handle,
const void *variant);
const void *variant);
/* Uploads CPU pixel data to a native texture. */
typedef void (*OakBackendUploadToTextureFn)(OakRenderBackendHandle handle,
const void *variant,
const void *video_params,
const void *data, int linesize);
const void *variant,
const void *video_params,
const void *data, int linesize);
/* Downloads native texture pixels into caller-owned CPU memory. */
typedef void (*OakBackendDownloadFromTextureFn)(OakRenderBackendHandle handle,
const void *variant,
const void *video_params,
void *data, int linesize);
const void *variant,
const void *video_params,
void *data, int linesize);
/* Waits for backend work that must be visible to later operations. */
typedef void (*OakBackendFlushFn)(OakRenderBackendHandle handle);
/* Reads one pixel from a texture. */
typedef void (*OakBackendGetPixelFromTextureFn)(OakRenderBackendHandle handle,
void *texture, const void *point,
void *out_color);
void *texture,
const void *point,
void *out_color);
/* Executes a shader blit job. */
typedef void (*OakBackendBlitFn)(OakRenderBackendHandle handle,
const void *shader, void *job,
@@ -108,7 +108,7 @@ typedef void (*OakBackendBlitFn)(OakRenderBackendHandle handle,
bool clear_destination);
/* Attaches an output texture for OFX OpenGL rendering when supported. */
typedef void (*OakBackendAttachOutputTextureFn)(OakRenderBackendHandle handle,
const void *texture_id);
const void *texture_id);
/* Detaches an OFX output texture when supported. */
typedef void (*OakBackendDetachOutputTextureFn)(OakRenderBackendHandle handle);
/* Returns the backend OpenGL context, or null for non-OpenGL backends. */
+17 -14
View File
@@ -114,7 +114,7 @@ bool Renderer::GetColorContext(const ColorTransformJob &color_job,
color_ctx.lut3d_textures[i].name = sampler_name;
color_ctx.lut3d_textures[i].interpolation =
(interpolation == OCIO::INTERP_NEAREST) ? Texture::kNearest :
Texture::kLinear;
Texture::kLinear;
}
color_ctx.lut1d_textures.resize(shader_desc->getNumTextures());
@@ -125,7 +125,8 @@ bool Renderer::GetColorContext(const ColorTransformJob &color_job,
OCIO::GpuShaderDesc::TextureType channel =
OCIO::GpuShaderDesc::TEXTURE_RGB_CHANNEL;
OCIO::Interpolation interpolation = OCIO::INTERP_LINEAR;
#if OCIO_VERSION_MAJOR > 2 || (OCIO_VERSION_MAJOR == 2 && OCIO_VERSION_MINOR >= 3)
#if OCIO_VERSION_MAJOR > 2 || \
(OCIO_VERSION_MAJOR == 2 && OCIO_VERSION_MINOR >= 3)
OCIO::GpuShaderDesc::TextureDimensions dimensions =
OCIO::GpuShaderDesc::TEXTURE_2D;
shader_desc->getTexture(i, tex_name, sampler_name, width, height,
@@ -149,16 +150,18 @@ bool Renderer::GetColorContext(const ColorTransformJob &color_job,
}
// Allocate 1D LUT
int lut_channels = (channel ==
OCIO::GpuShaderDesc::TEXTURE_RED_CHANNEL) ?
1 :
VideoParams::kRGBChannelCount;
VideoParams lut_params(width, height, PixelFormat::F32, lut_channels);
color_ctx.lut1d_textures[i].texture = CreateTexture(lut_params, values);
int lut_channels =
(channel == OCIO::GpuShaderDesc::TEXTURE_RED_CHANNEL) ?
1 :
VideoParams::kRGBChannelCount;
VideoParams lut_params(width, height, PixelFormat::F32,
lut_channels);
color_ctx.lut1d_textures[i].texture =
CreateTexture(lut_params, values);
color_ctx.lut1d_textures[i].name = sampler_name;
color_ctx.lut1d_textures[i].interpolation =
(interpolation == OCIO::INTERP_NEAREST) ? Texture::kNearest :
Texture::kLinear;
Texture::kLinear;
}
locker.relock();
@@ -176,9 +179,9 @@ void Renderer::BlitColorManaged(const ColorTransformJob &color_job,
ShaderJob fallback_job;
fallback_job.Insert(QStringLiteral("ove_maintex"),
color_job.GetInputTexture());
fallback_job.Insert(
QStringLiteral("ove_mvpmat"),
NodeValue(NodeValue::kMatrix, color_job.GetTransformMatrix()));
fallback_job.Insert(QStringLiteral("ove_mvpmat"),
NodeValue(NodeValue::kMatrix,
color_job.GetTransformMatrix()));
if (destination) {
BlitToTexture(GetDefaultShader(), fallback_job, destination,
@@ -206,12 +209,12 @@ void Renderer::BlitColorManaged(const ColorTransformJob &color_job,
foreach (const ColorContext::LUT &l, color_ctx.lut3d_textures) {
job.Insert(l.name, NodeValue(NodeValue::kTexture,
QVariant::fromValue(l.texture)));
QVariant::fromValue(l.texture)));
job.SetInterpolation(l.name, l.interpolation);
}
foreach (const ColorContext::LUT &l, color_ctx.lut1d_textures) {
job.Insert(l.name, NodeValue(NodeValue::kTexture,
QVariant::fromValue(l.texture)));
QVariant::fromValue(l.texture)));
job.SetInterpolation(l.name, l.interpolation);
}
+11 -9
View File
@@ -29,8 +29,8 @@ namespace olive
{
ColorProcessor::ColorProcessor(ColorManager *config, const QString &input,
const ColorTransform &transform,
Direction direction)
const ColorTransform &transform,
Direction direction)
{
processor_ = nullptr;
cpu_processor_ = nullptr;
@@ -59,17 +59,18 @@ ColorProcessor::ColorProcessor(ColorManager *config, const QString &input,
display_transform->setDisplay(output.toUtf8());
display_transform->setView(view.toUtf8());
display_transform->setDirection(direction == kNormal ?
OCIO::TRANSFORM_DIR_FORWARD :
OCIO::TRANSFORM_DIR_INVERSE);
OCIO::TRANSFORM_DIR_FORWARD :
OCIO::TRANSFORM_DIR_INVERSE);
if (transform.look().isEmpty()) {
processor_ = ocio_config->getProcessor(display_transform);
} else {
auto group = OCIO::GroupTransform::Create();
const char *out_cs = OCIO::LookTransform::GetLooksResultColorSpace(
ocio_config, ocio_config->getCurrentContext(),
transform.look().toUtf8());
const char *out_cs =
OCIO::LookTransform::GetLooksResultColorSpace(
ocio_config, ocio_config->getCurrentContext(),
transform.look().toUtf8());
auto lt = OCIO::LookTransform::Create();
lt->setSrc(resolved_input.toUtf8());
@@ -105,7 +106,8 @@ ColorProcessor::ColorProcessor(ColorManager *config, const QString &input,
ColorProcessor::ColorProcessor(OCIO::ConstProcessorRcPtr processor)
{
processor_ = processor;
cpu_processor_ = processor_ ? processor_->getDefaultCPUProcessor() : nullptr;
cpu_processor_ = processor_ ? processor_->getDefaultCPUProcessor() :
nullptr;
}
void ColorProcessor::ConvertFrame(Frame *f)
@@ -151,7 +153,7 @@ ColorProcessorPtr ColorProcessor::Create(ColorManager *config,
Direction direction)
{
return std::make_shared<ColorProcessor>(config, input, transform,
direction);
direction);
}
ColorProcessorPtr ColorProcessor::Create(OCIO::ConstProcessorRcPtr processor)
+9 -9
View File
@@ -15,13 +15,13 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
render/ipc/frameslotpool.cpp
render/ipc/frameslotpool.h
render/ipc/ipcmessage.cpp
render/ipc/ipcmessage.h
render/ipc/sharedmemoryregion.cpp
render/ipc/sharedmemoryregion.h
render/ipc/spscringbuffer.h
PARENT_SCOPE
${OLIVE_SOURCES}
render/ipc/frameslotpool.cpp
render/ipc/frameslotpool.h
render/ipc/ipcmessage.cpp
render/ipc/ipcmessage.h
render/ipc/sharedmemoryregion.cpp
render/ipc/sharedmemoryregion.h
render/ipc/spscringbuffer.h
PARENT_SCOPE
)
+17 -11
View File
@@ -36,18 +36,21 @@ size_t AlignUp(size_t value, size_t align)
return (value + (align - 1)) & ~(align - 1);
}
constexpr size_t kAlign = 64; // Cache-line alignment for each sub-region.
constexpr size_t kAlign = 64; // Cache-line alignment for each sub-region.
} // namespace
} // namespace
size_t FrameSlotPool::BytesNeeded(uint32_t slot_count, size_t slot_data_bytes)
{
const uint32_t ring_cap = RingCapacity(slot_count);
size_t total = AlignUp(sizeof(Header), kAlign);
total += AlignUp(SpscRingBuffer::BytesNeeded(ring_cap), kAlign); // free ring
total += AlignUp(SpscRingBuffer::BytesNeeded(ring_cap), kAlign); // ready ring
total += AlignUp(sizeof(FrameSlotMeta) * slot_count, kAlign); // metadata array
total += AlignUp(slot_data_bytes, kAlign) * slot_count; // pixel data blocks
total +=
AlignUp(SpscRingBuffer::BytesNeeded(ring_cap), kAlign); // free ring
total +=
AlignUp(SpscRingBuffer::BytesNeeded(ring_cap), kAlign); // ready ring
total +=
AlignUp(sizeof(FrameSlotMeta) * slot_count, kAlign); // metadata array
total += AlignUp(slot_data_bytes, kAlign) * slot_count; // pixel data blocks
return total;
}
@@ -111,9 +114,12 @@ FrameSlotPool FrameSlotPool::Attach(void *mem)
return pool;
}
pool.free_ring_ = SpscRingBuffer::Attach(pool.base_ + pool.header_->free_ring_offset);
pool.ready_ring_ = SpscRingBuffer::Attach(pool.base_ + pool.header_->ready_ring_offset);
pool.meta_ = reinterpret_cast<FrameSlotMeta *>(pool.base_ + pool.header_->meta_offset);
pool.free_ring_ =
SpscRingBuffer::Attach(pool.base_ + pool.header_->free_ring_offset);
pool.ready_ring_ =
SpscRingBuffer::Attach(pool.base_ + pool.header_->ready_ring_offset);
pool.meta_ = reinterpret_cast<FrameSlotMeta *>(pool.base_ +
pool.header_->meta_offset);
pool.data_ = pool.base_ + pool.header_->data_offset;
return pool;
@@ -169,5 +175,5 @@ bool FrameSlotPool::Release(uint32_t index)
return free_ring_->Push(index);
}
} // namespace ipc
} // namespace olive
} // namespace ipc
} // namespace olive
+13 -13
View File
@@ -40,16 +40,16 @@ namespace ipc
* not guaranteed shared-memory-safe).
*/
struct FrameSlotMeta {
int64_t id; ///< Caller-defined tag (e.g. ticket id, or footage stream hash).
int64_t time_num; ///< Frame timestamp numerator.
int64_t time_den; ///< Frame timestamp denominator.
int64_t id; ///< Caller-defined tag (e.g. ticket id, or footage stream hash).
int64_t time_num; ///< Frame timestamp numerator.
int64_t time_den; ///< Frame timestamp denominator.
int32_t width;
int32_t height;
int32_t format; ///< olive::PixelFormat::Format value.
int32_t format; ///< olive::PixelFormat::Format value.
int32_t channel_count;
int32_t linesize; ///< Bytes per scanline (stride).
int32_t data_size; ///< Valid bytes written into the slot's data block.
char colorspace[128]; ///< Input colorspace name for color-managed footage.
int32_t linesize; ///< Bytes per scanline (stride).
int32_t data_size; ///< Valid bytes written into the slot's data block.
char colorspace[128]; ///< Input colorspace name for color-managed footage.
};
/**
@@ -90,7 +90,8 @@ public:
* Initializes both rings, seeds the free ring with every slot index, and zeroes metadata.
* `mem` must provide at least BytesNeeded(slot_count, slot_data_bytes) bytes.
*/
static FrameSlotPool Create(void *mem, uint32_t slot_count, size_t slot_data_bytes);
static FrameSlotPool Create(void *mem, uint32_t slot_count,
size_t slot_data_bytes);
/**
* @brief Map an existing, already-initialized pool (peer side).
@@ -148,7 +149,6 @@ public:
FrameSlotPool() = default;
private:
struct Header {
uint32_t magic;
uint32_t slot_count;
@@ -160,7 +160,7 @@ private:
uint64_t data_offset;
};
static constexpr uint32_t kMagic = 0x4F4B5350; // 'OKSP'
static constexpr uint32_t kMagic = 0x4F4B5350; // 'OKSP'
// Ring capacity must exceed slot_count by one because a ring can hold at most capacity-1 entries
// and we need to be able to enqueue every slot at once.
@@ -177,7 +177,7 @@ private:
uint8_t *data_ = nullptr;
};
} // namespace ipc
} // namespace olive
} // namespace ipc
} // namespace olive
#endif // IPC_FRAMESLOTPOOL_H
#endif // IPC_FRAMESLOTPOOL_H
+2 -2
View File
@@ -227,5 +227,5 @@ bool LoadGraphMsg::FromJson(const QJsonObject &o, LoadGraphMsg *out)
return true;
}
} // namespace ipc
} // namespace olive
} // namespace ipc
} // namespace olive
+25 -20
View File
@@ -63,7 +63,7 @@ constexpr const char *kCancel = "cancel";
constexpr const char *kGraphUpdate = "graph_update";
constexpr const char *kShutdown = "shutdown";
constexpr const char *kError = "error";
} // namespace msgtype
} // namespace msgtype
/**
* @brief Write one NDJSON message line to `device`.
@@ -92,29 +92,34 @@ bool ReadMessage(QByteArray *buffer, QJsonObject *out, bool *ok = nullptr);
struct HandshakeMsg {
int protocol_version = 0;
QString shm_key; ///< Worker->main output shared-memory segment key.
QString input_shm_key; ///< Main->worker input shared-memory segment key (optional).
int input_slots = 0; ///< Number of main->worker input frame slots.
int output_slots = 0; ///< Number of worker->main output frame slots.
qint64 slot_data_bytes = 0; ///< Per-output-slot pixel block size.
qint64 input_slot_data_bytes = 0; ///< Per-input-slot pixel block size.
QString shm_key; ///< Worker->main output shared-memory segment key.
QString
input_shm_key; ///< Main->worker input shared-memory segment key (optional).
int input_slots = 0; ///< Number of main->worker input frame slots.
int output_slots = 0; ///< Number of worker->main output frame slots.
qint64 slot_data_bytes = 0; ///< Per-output-slot pixel block size.
qint64 input_slot_data_bytes = 0; ///< Per-input-slot pixel block size.
QJsonObject ToJson() const;
static bool FromJson(const QJsonObject &o, HandshakeMsg *out);
};
struct RenderFrameMsg {
qint64 ticket_id = 0; ///< Correlates this request with the eventual frame_ready.
QString node_uuid; ///< Output/viewer node to render, by stable uuid in the loaded graph.
qint64 ticket_id =
0; ///< Correlates this request with the eventual frame_ready.
QString
node_uuid; ///< Output/viewer node to render, by stable uuid in the loaded graph.
qint64 time_num = 0;
qint64 time_den = 1;
int width = 0; ///< Forced output size (0 = use graph default).
int width = 0; ///< Forced output size (0 = use graph default).
int height = 0;
int format = -1; ///< Forced PixelFormat::Format (-1 = default/INVALID).
int channel_count = 0; ///< 0 = default.
int mode = 0; ///< RenderMode::Mode.
int input_slot = -1; ///< Optional main->worker decoded input slot for footage nodes.
QVector<int> input_slots; ///< Optional ordered decoded input slots for footage nodes.
int format = -1; ///< Forced PixelFormat::Format (-1 = default/INVALID).
int channel_count = 0; ///< 0 = default.
int mode = 0; ///< RenderMode::Mode.
int input_slot =
-1; ///< Optional main->worker decoded input slot for footage nodes.
QVector<int>
input_slots; ///< Optional ordered decoded input slots for footage nodes.
// Output color transform to apply before returning the frame. When empty,
// the worker returns the image in the project's reference space.
@@ -130,7 +135,7 @@ struct RenderFrameMsg {
struct FrameReadyMsg {
qint64 ticket_id = 0;
int output_slot = 0; ///< Index into the worker->main output FrameSlotPool.
int output_slot = 0; ///< Index into the worker->main output FrameSlotPool.
QJsonObject ToJson() const;
static bool FromJson(const QJsonObject &o, FrameReadyMsg *out);
@@ -144,13 +149,13 @@ struct CancelMsg {
};
struct LoadGraphMsg {
QString path; ///< Temporary file holding the serialized node graph.
QString path; ///< Temporary file holding the serialized node graph.
QJsonObject ToJson() const;
static bool FromJson(const QJsonObject &o, LoadGraphMsg *out);
};
} // namespace ipc
} // namespace olive
} // namespace ipc
} // namespace olive
#endif // IPC_IPCMESSAGE_H
#endif // IPC_IPCMESSAGE_H
+16 -10
View File
@@ -75,16 +75,20 @@ bool SharedMemoryRegion::Open(const QString &key, size_t size, Mode mode)
const std::wstring wname = mapping_name.toStdWString();
if (mode == kCreate) {
const DWORD size_high = static_cast<DWORD>((quint64(size) >> 32) & 0xFFFFFFFF);
const DWORD size_high =
static_cast<DWORD>((quint64(size) >> 32) & 0xFFFFFFFF);
const DWORD size_low = static_cast<DWORD>(quint64(size) & 0xFFFFFFFF);
handle_ = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE,
size_high, size_low, wname.c_str());
handle_ = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr,
PAGE_READWRITE, size_high, size_low,
wname.c_str());
if (!handle_) {
error_ = QStringLiteral("CreateFileMapping failed: %1").arg(GetLastError());
error_ = QStringLiteral("CreateFileMapping failed: %1")
.arg(GetLastError());
return false;
}
if (GetLastError() == ERROR_ALREADY_EXISTS) {
error_ = QStringLiteral("Shared memory key already exists: %1").arg(key);
error_ =
QStringLiteral("Shared memory key already exists: %1").arg(key);
CloseHandle(handle_);
handle_ = nullptr;
return false;
@@ -92,7 +96,8 @@ bool SharedMemoryRegion::Open(const QString &key, size_t size, Mode mode)
} else {
handle_ = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, wname.c_str());
if (!handle_) {
error_ = QStringLiteral("OpenFileMapping failed: %1").arg(GetLastError());
error_ =
QStringLiteral("OpenFileMapping failed: %1").arg(GetLastError());
return false;
}
}
@@ -124,7 +129,7 @@ void SharedMemoryRegion::Close()
size_ = 0;
}
#else // POSIX
#else // POSIX
bool SharedMemoryRegion::Open(const QString &key, size_t size, Mode mode)
{
@@ -165,7 +170,8 @@ bool SharedMemoryRegion::Open(const QString &key, size_t size, Mode mode)
data_ = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_, 0);
if (data_ == MAP_FAILED) {
error_ = QStringLiteral("mmap failed: %1").arg(QString::fromUtf8(strerror(errno)));
error_ = QStringLiteral("mmap failed: %1")
.arg(QString::fromUtf8(strerror(errno)));
data_ = nullptr;
::close(fd_);
fd_ = -1;
@@ -201,5 +207,5 @@ void SharedMemoryRegion::Close()
#endif
} // namespace ipc
} // namespace olive
} // namespace ipc
} // namespace olive
+6 -6
View File
@@ -110,14 +110,14 @@ private:
QString error_;
#if defined(Q_OS_WIN)
void *handle_; // HANDLE from CreateFileMapping/OpenFileMapping
void *handle_; // HANDLE from CreateFileMapping/OpenFileMapping
#else
int fd_; // file descriptor from shm_open
QString shm_name_; // the platform-prefixed name actually passed to shm_open
int fd_; // file descriptor from shm_open
QString shm_name_; // the platform-prefixed name actually passed to shm_open
#endif
};
} // namespace ipc
} // namespace olive
} // namespace ipc
} // namespace olive
#endif // IPC_SHAREDMEMORYREGION_H
#endif // IPC_SHAREDMEMORYREGION_H
+6 -5
View File
@@ -174,11 +174,12 @@ private:
std::atomic<uint32_t> tail_;
uint32_t capacity_;
static_assert(sizeof(std::atomic<uint32_t>) == sizeof(uint32_t),
"atomic<uint32_t> must be lock-free POD-sized for shared memory use");
static_assert(
sizeof(std::atomic<uint32_t>) == sizeof(uint32_t),
"atomic<uint32_t> must be lock-free POD-sized for shared memory use");
};
} // namespace ipc
} // namespace olive
} // namespace ipc
} // namespace olive
#endif // IPC_SPSCRINGBUFFER_H
#endif // IPC_SPSCRINGBUFFER_H
+9 -9
View File
@@ -16,14 +16,14 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
render/job/acceleratedjob.cpp
render/job/acceleratedjob.h
render/job/footagejob.h
render/job/generatejob.h
render/job/samplejob.h
render/job/shaderjob.h
render/job/pluginjob.h
render/job/pluginjob.cpp
${OLIVE_SOURCES}
render/job/acceleratedjob.cpp
render/job/acceleratedjob.h
render/job/footagejob.h
render/job/generatejob.h
render/job/samplejob.h
render/job/shaderjob.h
render/job/pluginjob.h
render/job/pluginjob.cpp
PARENT_SCOPE
)
+4 -2
View File
@@ -19,7 +19,9 @@
#include "pluginjob.h"
namespace olive {
namespace plugin {
namespace olive
{
namespace plugin
{
} // plugin
} // olive
+19 -14
View File
@@ -26,47 +26,52 @@
#include <any>
#include <chrono>
namespace olive {
namespace plugin {
namespace olive
{
namespace plugin
{
class PluginJob :public AcceleratedJob{
class PluginJob : public AcceleratedJob {
public:
explicit PluginJob(const OFX::Host::ImageEffect::Instance* pluginInstance,
const PluginNode* node, NodeValueRow row,
explicit PluginJob(const OFX::Host::ImageEffect::Instance *pluginInstance,
const PluginNode *node, NodeValueRow row,
const olive::core::rational &time)
: AcceleratedJob()
, time_seconds_(time.toDouble())
{
this->pluginInstance_ = pluginInstance;
this->node_=node;
this->node_ = node;
Insert(row);
}
explicit PluginJob(const OFX::Host::ImageEffect::Instance* pluginInstance,
const PluginNode* node, NodeValueRow row)
explicit PluginJob(const OFX::Host::ImageEffect::Instance *pluginInstance,
const PluginNode *node, NodeValueRow row)
: PluginJob(pluginInstance, node, row, olive::core::rational(0))
{
}
PluginNode *node() const {
PluginNode *node() const
{
return const_cast<PluginNode *>(node_);
}
OFX::Host::ImageEffect::Instance* pluginInstance() {
return const_cast<OFX::Host::ImageEffect::Instance*>(pluginInstance_);
OFX::Host::ImageEffect::Instance *pluginInstance()
{
return const_cast<OFX::Host::ImageEffect::Instance *>(pluginInstance_);
}
double time_seconds() const {
double time_seconds() const
{
return time_seconds_;
}
private:
const OFX::Host::ImageEffect::Instance *pluginInstance_=nullptr;
const OFX::Host::ImageEffect::Instance *pluginInstance_ = nullptr;
QHash<OfxTime, QHash<QString, std::any>> paramsOnTime;
QHash<QString, std::any> params;
const PluginNode *node_=nullptr;
const PluginNode *node_ = nullptr;
double time_seconds_ = 0.0;
};
+7 -7
View File
@@ -16,14 +16,14 @@
file(GLOB_RECURSE OCIOCONF_RESOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.ocio *.spi3d *.spi1d)
set(QRC_BODY "")
foreach(OCIOCONF_FILE ${OCIOCONF_RESOURCES})
string(APPEND QRC_BODY "<file>${OCIOCONF_FILE}</file>\n")
configure_file(${OCIOCONF_FILE} ${OCIOCONF_FILE} COPYONLY)
endforeach()
foreach (OCIOCONF_FILE ${OCIOCONF_RESOURCES})
string(APPEND QRC_BODY "<file>${OCIOCONF_FILE}</file>\n")
configure_file(${OCIOCONF_FILE} ${OCIOCONF_FILE} COPYONLY)
endforeach ()
configure_file(ocioconf.qrc.in ocioconf.qrc @ONLY)
set(OLIVE_RESOURCES
${OLIVE_RESOURCES}
${CMAKE_CURRENT_BINARY_DIR}/ocioconf.qrc
PARENT_SCOPE
${OLIVE_RESOURCES}
${CMAKE_CURRENT_BINARY_DIR}/ocioconf.qrc
PARENT_SCOPE
)
+4 -4
View File
@@ -15,8 +15,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
render/opengl/openglrenderer.cpp
render/opengl/openglrenderer.h
PARENT_SCOPE
${OLIVE_SOURCES}
render/opengl/openglrenderer.cpp
render/opengl/openglrenderer.h
PARENT_SCOPE
)
+73 -54
View File
@@ -10,7 +10,8 @@
#include "render/texture.h"
#include "render/videoparams.h"
namespace {
namespace
{
class BackendOpenGLRenderer : public olive::OpenGLRenderer {
public:
@@ -39,29 +40,32 @@ const QVariant &VariantRef(const void *variant)
} // namespace
// Creates the backend object and returns it as an opaque C handle.
OAK_RENDER_BACKEND_EXPORT OakRenderBackendHandle oak_renderer_create(void *parent)
OAK_RENDER_BACKEND_EXPORT OakRenderBackendHandle
oak_renderer_create(void *parent)
{
return new BackendOpenGLRenderer(static_cast<QObject *>(parent));
}
// Destroys the opaque backend object created by oak_renderer_create().
OAK_RENDER_BACKEND_EXPORT void oak_renderer_destroy(OakRenderBackendHandle handle)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_destroy(OakRenderBackendHandle handle)
{
delete Renderer(handle);
}
// Reports static OpenGL backend capabilities to the adapter.
OAK_RENDER_BACKEND_EXPORT bool oak_renderer_get_info(
OakRenderBackendHandle handle, OakRenderBackendInfo *out_info)
OAK_RENDER_BACKEND_EXPORT bool
oak_renderer_get_info(OakRenderBackendHandle handle,
OakRenderBackendInfo *out_info)
{
if (!handle || !out_info) {
return false;
}
out_info->abi_version = 1;
out_info->kind = OAK_RENDER_BACKEND_OPENGL;
out_info->capabilities = OAK_RENDER_BACKEND_CAP_TEXTURES |
OAK_RENDER_BACKEND_CAP_SHADERS | OAK_RENDER_BACKEND_CAP_BLIT |
OAK_RENDER_BACKEND_CAP_READBACK |
out_info->capabilities =
OAK_RENDER_BACKEND_CAP_TEXTURES | OAK_RENDER_BACKEND_CAP_SHADERS |
OAK_RENDER_BACKEND_CAP_BLIT | OAK_RENDER_BACKEND_CAP_READBACK |
OAK_RENDER_BACKEND_CAP_VIEWER_CONTEXT;
out_info->name = "opengl";
out_info->status = "available";
@@ -70,8 +74,8 @@ OAK_RENDER_BACKEND_EXPORT bool oak_renderer_get_info(
// OpenGL availability is context-dependent, so object creation is the minimum
// availability signal for this backend.
OAK_RENDER_BACKEND_EXPORT bool oak_renderer_is_available(
OakRenderBackendHandle handle)
OAK_RENDER_BACKEND_EXPORT bool
oak_renderer_is_available(OakRenderBackendHandle handle)
{
return handle != nullptr;
}
@@ -83,38 +87,40 @@ OAK_RENDER_BACKEND_EXPORT bool oak_renderer_init(OakRenderBackendHandle handle)
}
// Initializes the backend against a caller-owned viewer OpenGL context.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_init_with_context(
OakRenderBackendHandle handle, void *context)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_init_with_context(OakRenderBackendHandle handle, void *context)
{
Renderer(handle)->Init(static_cast<QOpenGLContext *>(context));
}
// Runs renderer post-initialization once the GL context is available.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_post_init(OakRenderBackendHandle handle)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_post_init(OakRenderBackendHandle handle)
{
Renderer(handle)->PostInit();
}
// Releases post-init OpenGL surface/context state.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_post_destroy(OakRenderBackendHandle handle)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_post_destroy(OakRenderBackendHandle handle)
{
Renderer(handle)->PostDestroy();
}
// Releases renderer-owned GL resources before object destruction.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_destroy_internal(
OakRenderBackendHandle handle)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_destroy_internal(OakRenderBackendHandle handle)
{
Renderer(handle)->DestroyInternal();
}
// Clears either the widget framebuffer or a texture destination.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_clear_destination(
OakRenderBackendHandle handle, void *texture, double r, double g, double b,
double a)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_clear_destination(OakRenderBackendHandle handle, void *texture,
double r, double g, double b, double a)
{
Renderer(handle)->ClearDestination(static_cast<olive::Texture *>(texture),
r, g, b, a);
r, g, b, a);
}
// Creates an OpenGL texture and writes its QVariant handle to out_variant.
@@ -122,51 +128,58 @@ OAK_RENDER_BACKEND_EXPORT void oak_renderer_create_native_texture(
OakRenderBackendHandle handle, int width, int height, int depth, int format,
int channel_count, const void *data, int linesize, void *out_variant)
{
*static_cast<QVariant *>(out_variant) = Renderer(handle)->CreateNativeTexture(
width, height, depth, static_cast<olive::PixelFormat::Format>(format),
channel_count, data, linesize);
*static_cast<QVariant *>(out_variant) =
Renderer(handle)->CreateNativeTexture(
width, height, depth,
static_cast<olive::PixelFormat::Format>(format), channel_count,
data, linesize);
}
// Destroys an OpenGL texture represented by a QVariant handle.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_destroy_native_texture(
OakRenderBackendHandle handle, const void *variant)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_destroy_native_texture(OakRenderBackendHandle handle,
const void *variant)
{
Renderer(handle)->DestroyNativeTexture(VariantRef(variant));
}
// Compiles an OpenGL shader program and returns its QVariant handle.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_create_native_shader(
OakRenderBackendHandle handle, const void *shader_code, void *out_variant)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_create_native_shader(OakRenderBackendHandle handle,
const void *shader_code, void *out_variant)
{
*static_cast<QVariant *>(out_variant) = Renderer(handle)->CreateNativeShader(
*static_cast<const olive::ShaderCode *>(shader_code));
*static_cast<QVariant *>(out_variant) =
Renderer(handle)->CreateNativeShader(
*static_cast<const olive::ShaderCode *>(shader_code));
}
// Destroys an OpenGL shader program represented by a QVariant handle.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_destroy_native_shader(
OakRenderBackendHandle handle, const void *variant)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_destroy_native_shader(OakRenderBackendHandle handle,
const void *variant)
{
Renderer(handle)->DestroyNativeShader(VariantRef(variant));
}
// Uploads CPU pixel data into an OpenGL texture.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_upload_to_texture(
OakRenderBackendHandle handle, const void *variant, const void *video_params,
const void *data, int linesize)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_upload_to_texture(OakRenderBackendHandle handle,
const void *variant, const void *video_params,
const void *data, int linesize)
{
Renderer(handle)->UploadToTexture(
VariantRef(variant), *static_cast<const olive::VideoParams *>(video_params),
data, linesize);
VariantRef(variant),
*static_cast<const olive::VideoParams *>(video_params), data, linesize);
}
// Reads an OpenGL texture back to CPU memory.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_download_from_texture(
OakRenderBackendHandle handle, const void *variant, const void *video_params,
void *data, int linesize)
OakRenderBackendHandle handle, const void *variant,
const void *video_params, void *data, int linesize)
{
Renderer(handle)->DownloadFromTexture(
VariantRef(variant), *static_cast<const olive::VideoParams *>(video_params),
data, linesize);
VariantRef(variant),
*static_cast<const olive::VideoParams *>(video_params), data, linesize);
}
// Flushes/waits for pending OpenGL work as required by the renderer.
@@ -176,18 +189,23 @@ OAK_RENDER_BACKEND_EXPORT void oak_renderer_flush(OakRenderBackendHandle handle)
}
// Reads one pixel from an OpenGL texture.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_get_pixel_from_texture(
OakRenderBackendHandle handle, void *texture, const void *point,
void *out_color)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_get_pixel_from_texture(OakRenderBackendHandle handle,
void *texture, const void *point,
void *out_color)
{
*static_cast<olive::Color *>(out_color) = Renderer(handle)->GetPixelFromTexture(
static_cast<olive::Texture *>(texture), *static_cast<const QPointF *>(point));
*static_cast<olive::Color *>(out_color) =
Renderer(handle)->GetPixelFromTexture(
static_cast<olive::Texture *>(texture),
*static_cast<const QPointF *>(point));
}
// Executes a shader blit through the wrapped C++ OpenGL renderer.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_blit(
OakRenderBackendHandle handle, const void *shader, void *job,
void *destination, const void *destination_params, bool clear_destination)
OAK_RENDER_BACKEND_EXPORT void oak_renderer_blit(OakRenderBackendHandle handle,
const void *shader, void *job,
void *destination,
const void *destination_params,
bool clear_destination)
{
Renderer(handle)->Blit(
VariantRef(shader), *static_cast<olive::AcceleratedJob *>(job),
@@ -197,22 +215,23 @@ OAK_RENDER_BACKEND_EXPORT void oak_renderer_blit(
}
// Exposes the wrapped OpenGL context for GL-specific integrations.
OAK_RENDER_BACKEND_EXPORT void *oak_renderer_opengl_context(
OakRenderBackendHandle handle)
OAK_RENDER_BACKEND_EXPORT void *
oak_renderer_opengl_context(OakRenderBackendHandle handle)
{
return Renderer(handle)->context();
}
// Binds an output texture for OFX OpenGL rendering.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_attach_output_texture(
OakRenderBackendHandle handle, const void *texture_id)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_attach_output_texture(OakRenderBackendHandle handle,
const void *texture_id)
{
Renderer(handle)->AttachTextureAsDestination(VariantRef(texture_id));
}
// Detaches any OFX OpenGL output texture binding.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_detach_output_texture(
OakRenderBackendHandle handle)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_detach_output_texture(OakRenderBackendHandle handle)
{
Renderer(handle)->DetachTextureAsDestination();
}
+58 -45
View File
@@ -265,8 +265,8 @@ void OpenGLRenderer::AttachTextureAsDestination(const QVariant &texture)
void OpenGLRenderer::DetachTextureAsDestination()
{
// QOpenGLWidget renders to a non-zero default FBO.
const GLuint default_fbo =
context_ ? context_->defaultFramebufferObject() : 0;
const GLuint default_fbo = context_ ? context_->defaultFramebufferObject() :
0;
functions_->glBindFramebuffer(GL_FRAMEBUFFER, default_fbo);
}
@@ -504,8 +504,8 @@ struct TextureToBind {
Texture::Interpolation interpolation;
};
void OpenGLRenderer::Blit(QVariant s, AcceleratedJob& a_job, Texture *destination,
VideoParams destination_params,
void OpenGLRenderer::Blit(QVariant s, AcceleratedJob &a_job,
Texture *destination, VideoParams destination_params,
bool clear_destination)
{
GL_PREAMBLE;
@@ -519,7 +519,7 @@ void OpenGLRenderer::Blit(QVariant s, AcceleratedJob& a_job, Texture *destinatio
functions_->glBindFramebuffer(GL_FRAMEBUFFER, fbo);
}
ShaderJob &s_job=dynamic_cast<ShaderJob &>(a_job);
ShaderJob &s_job = dynamic_cast<ShaderJob &>(a_job);
ShaderJob job(s_job);
// If this node is iterative, we'll pick up which input here
QMap<QString, GLuint> texture_index_map;
@@ -585,7 +585,8 @@ void OpenGLRenderer::Blit(QVariant s, AcceleratedJob& a_job, Texture *destinatio
case NodeValue::kColor: {
Color color = value.toColor();
functions_->glUniform4f(variable_location, color.red(),
color.green(), color.blue(), color.alpha());
color.green(), color.blue(),
color.alpha());
break;
}
case NodeValue::kBoolean:
@@ -595,7 +596,8 @@ void OpenGLRenderer::Blit(QVariant s, AcceleratedJob& a_job, Texture *destinatio
TexturePtr texture = value.toTexture();
// Set value to bound texture
functions_->glUniform1i(variable_location, textures_to_bind.size());
functions_->glUniform1i(variable_location,
textures_to_bind.size());
texture_index_map.insert(it.key(), textures_to_bind.size());
@@ -605,8 +607,10 @@ void OpenGLRenderer::Blit(QVariant s, AcceleratedJob& a_job, Texture *destinatio
// Set enable flag if shader wants it
GLuint tex_id = texture ? texture->id().value<GLuint>() : 0;
int enable_param_location = functions_->glGetUniformLocation(
shader,
QStringLiteral("%1_enabled").arg(it.key()).toUtf8().constData());
shader, QStringLiteral("%1_enabled")
.arg(it.key())
.toUtf8()
.constData());
if (enable_param_location > -1) {
functions_->glUniform1i(enable_param_location, tex_id > 0);
}
@@ -637,8 +641,9 @@ void OpenGLRenderer::Blit(QVariant s, AcceleratedJob& a_job, Texture *destinatio
functions_->glActiveTexture(GL_TEXTURE0 + i);
GLenum target = (texture && texture->params().is_3d()) ? GL_TEXTURE_3D :
GL_TEXTURE_2D;
GLenum target = (texture && texture->params().is_3d()) ?
GL_TEXTURE_3D :
GL_TEXTURE_2D;
functions_->glBindTexture(target, tex_id);
if (tex_id) {
@@ -647,12 +652,12 @@ void OpenGLRenderer::Blit(QVariant s, AcceleratedJob& a_job, Texture *destinatio
if (texture->channel_count() == 1 &&
destination_params.channel_count() != 1) {
// Interpret this texture as a grayscale texture
functions_->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R,
GL_RED);
functions_->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G,
GL_RED);
functions_->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B,
GL_RED);
functions_->glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_SWIZZLE_R, GL_RED);
functions_->glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_SWIZZLE_G, GL_RED);
functions_->glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_SWIZZLE_B, GL_RED);
}
}
}
@@ -683,7 +688,8 @@ void OpenGLRenderer::Blit(QVariant s, AcceleratedJob& a_job, Texture *destinatio
if (!job.GetVertexCoordinates().isEmpty()) {
Q_ASSERT(job.GetVertexCoordinates().size() == 18);
vert_vbo_.allocate(job.GetVertexCoordinates().constData(),
job.GetVertexCoordinates().size() * sizeof(float));
job.GetVertexCoordinates().size() *
sizeof(float));
} else {
vert_vbo_.allocate(blit_vertices.constData(),
blit_vertices.size() * sizeof(GLfloat));
@@ -707,12 +713,13 @@ void OpenGLRenderer::Blit(QVariant s, AcceleratedJob& a_job, Texture *destinatio
vert_vbo_.release();
}
GLint tex_location = functions_->glGetAttribLocation(shader, "a_texcoord");
GLint tex_location =
functions_->glGetAttribLocation(shader, "a_texcoord");
if (tex_location != -1) {
frag_vbo_.bind();
functions_->glEnableVertexAttribArray(tex_location);
functions_->glVertexAttribPointer(tex_location, 2, GL_FLOAT, GL_FALSE,
0, nullptr);
functions_->glVertexAttribPointer(tex_location, 2, GL_FLOAT,
GL_FALSE, 0, nullptr);
frag_vbo_.release();
}
@@ -788,9 +795,9 @@ void OpenGLRenderer::Blit(QVariant s, AcceleratedJob& a_job, Texture *destinatio
// Blit this texture through this shader
{
PRINT_GL_ERRORS;
functions_->glDrawArrays(GL_TRIANGLES, 0, blit_vertices.size() / 3);
functions_->glDrawArrays(GL_TRIANGLES, 0,
blit_vertices.size() / 3);
}
}
if (destination) {
@@ -801,8 +808,9 @@ void OpenGLRenderer::Blit(QVariant s, AcceleratedJob& a_job, Texture *destinatio
// Release any textures we bound before
for (int i = textures_to_bind.size() - 1; i >= 0; i--) {
TexturePtr texture = textures_to_bind.at(i).texture;
GLenum target = (texture && texture->params().is_3d()) ? GL_TEXTURE_3D :
GL_TEXTURE_2D;
GLenum target = (texture && texture->params().is_3d()) ?
GL_TEXTURE_3D :
GL_TEXTURE_2D;
functions_->glActiveTexture(GL_TEXTURE0 + i);
functions_->glBindTexture(target, 0);
}
@@ -815,9 +823,8 @@ void OpenGLRenderer::Blit(QVariant s, AcceleratedJob& a_job, Texture *destinatio
vert_vbo_.destroy();
vao_.release();
vao_.destroy();
} catch (std::bad_cast e) {
}
catch (std::bad_cast e){}
}
GLint OpenGLRenderer::GetInternalFormat(PixelFormat format, int channel_layout)
@@ -965,12 +972,12 @@ GLuint OpenGLRenderer::CompileShader(GLenum type, const QString &code)
const int major = context_ ? context_->format().majorVersion() : 0;
const int minor = context_ ? context_->format().minorVersion() : 0;
const bool is_gles2 = is_gles && (major < 3);
const QString gles_preamble = is_gles2
? QStringLiteral("#version 100\n\n"
"precision highp float;\n\n"
"#define frag_color gl_FragColor\n")
: QStringLiteral("#version 300 es\n\n"
"precision highp float;\n\n");
const QString gles_preamble =
is_gles2 ? QStringLiteral("#version 100\n\n"
"precision highp float;\n\n"
"#define frag_color gl_FragColor\n") :
QStringLiteral("#version 300 es\n\n"
"precision highp float;\n\n");
const QString desktop_preamble =
// Use appropriate GL 3.2 shader header
QStringLiteral("#version 150\n\n"
@@ -991,7 +998,8 @@ GLuint OpenGLRenderer::CompileShader(GLenum type, const QString &code)
QString complete_code;
if (base_code.startsWith(QStringLiteral("#version"))) {
if (is_gles || !desktop_preamble.startsWith(QStringLiteral("#version"))) {
if (is_gles ||
!desktop_preamble.startsWith(QStringLiteral("#version"))) {
int newline = base_code.indexOf('\n');
if (newline >= 0) {
complete_code = shader_preamble + base_code.mid(newline + 1);
@@ -1007,18 +1015,22 @@ GLuint OpenGLRenderer::CompileShader(GLenum type, const QString &code)
if (is_gles2) {
if (type == GL_VERTEX_SHADER) {
complete_code.replace(QRegularExpression(QStringLiteral("\\bin\\b")),
QStringLiteral("attribute"));
complete_code.replace(QRegularExpression(QStringLiteral("\\bout\\b")),
QStringLiteral("varying"));
complete_code.replace(
QRegularExpression(QStringLiteral("\\bin\\b")),
QStringLiteral("attribute"));
complete_code.replace(
QRegularExpression(QStringLiteral("\\bout\\b")),
QStringLiteral("varying"));
} else if (type == GL_FRAGMENT_SHADER) {
complete_code.replace(QRegularExpression(QStringLiteral("\\bin\\b")),
QStringLiteral("varying"));
complete_code.replace(QRegularExpression(
QStringLiteral("\\bout\\s+vec4\\s+frag_color\\s*;")),
complete_code.replace(
QRegularExpression(QStringLiteral("\\bin\\b")),
QStringLiteral("varying"));
complete_code.replace(QRegularExpression(QStringLiteral(
"\\bout\\s+vec4\\s+frag_color\\s*;")),
QStringLiteral("// frag_color output"));
complete_code.replace(QRegularExpression(QStringLiteral("\\btexture\\b")),
QStringLiteral("texture2D"));
complete_code.replace(
QRegularExpression(QStringLiteral("\\btexture\\b")),
QStringLiteral("texture2D"));
}
}
@@ -1058,7 +1070,8 @@ bool OpenGLRenderer::EnsureContextCurrent(const char *caller)
// paint code can receive textures produced by a render-thread OpenGL
// renderer, so guard here before makeCurrent() can crash inside Qt/GL.
if (context_->thread() != QThread::currentThread()) {
qWarning() << caller << "called from the wrong thread for this OpenGL context";
qWarning()
<< caller << "called from the wrong thread for this OpenGL context";
return false;
}
+1 -1
View File
@@ -94,7 +94,7 @@ public:
bool EnsureContextCurrent(const char *caller);
protected:
virtual void Blit(QVariant shader, olive::AcceleratedJob& job,
virtual void Blit(QVariant shader, olive::AcceleratedJob &job,
olive::Texture *destination,
olive::VideoParams destination_params,
bool clear_destination) override;
File diff suppressed because it is too large Load Diff
+14 -8
View File
@@ -31,8 +31,10 @@
namespace olive
{
namespace plugin{
namespace detail {
namespace plugin
{
namespace detail
{
// 作用:将字节行跨度转换为像素跨度,便于纹理读写。
// Purpose: Convert byte stride to pixel stride for texture I/O.
int BytesToPixels(int byte_linesize, const olive::VideoParams &params);
@@ -46,9 +48,15 @@ int BytesToPixels(int byte_linesize, const olive::VideoParams &params);
class PluginRenderer : public QObject {
Q_OBJECT
public:
explicit PluginRenderer(olive::Renderer *renderer, QObject *parent = nullptr)
: QObject(parent), renderer_(renderer) {}
virtual ~PluginRenderer() override {}
explicit PluginRenderer(olive::Renderer *renderer,
QObject *parent = nullptr)
: QObject(parent)
, renderer_(renderer)
{
}
virtual ~PluginRenderer() override
{
}
olive::Renderer *renderer() const
{
@@ -63,7 +71,7 @@ public:
void DetachOutputTexture();
// 作用:执行插件渲染流程(参数配置、输入/输出、调用渲染动作)。
// Purpose: Execute plugin render flow (params, inputs/outputs, render actions).
void RenderPlugin(TexturePtr src, olive::plugin::PluginJob& job,
void RenderPlugin(TexturePtr src, olive::plugin::PluginJob &job,
olive::TexturePtr destination,
olive::VideoParams destination_params,
bool clear_destination, bool interactive);
@@ -74,6 +82,4 @@ private:
}
}
#endif //PLUGINRENDERER_H
+6 -3
View File
@@ -561,7 +561,8 @@ void PreviewAutoCacher::TryRender()
video_immediate_passthroughs_[watcher].append(t);
}
} else {
qWarning() << "Failed to find copied node for SFR ticket, requeueing";
qWarning()
<< "Failed to find copied node for SFR ticket, requeueing";
single_frame_render_ = t;
if (!delayed_requeue_timer_.isActive()) {
delayed_requeue_timer_.start();
@@ -594,7 +595,8 @@ void PreviewAutoCacher::TryRender()
}
}
} else {
qWarning() << "Failed to find node copy for video job, retrying";
qWarning()
<< "Failed to find node copy for video job, retrying";
if (!delayed_requeue_timer_.isActive()) {
delayed_requeue_timer_.start();
}
@@ -636,7 +638,8 @@ void PreviewAutoCacher::TryRender()
RenderAudio(copy, d.context, use_range, d.cache);
} else {
qWarning() << "Failed to find node copy for audio job, retrying";
qWarning()
<< "Failed to find node copy for audio job, retrying";
pop = false;
if (!delayed_requeue_timer_.isActive()) {
delayed_requeue_timer_.start();
+9 -6
View File
@@ -265,7 +265,9 @@ void ProjectCopier::InsertIntoCopyMap(Node *node, Node *copy)
if (Footage *src_footage = dynamic_cast<Footage *>(node)) {
if (dynamic_cast<Footage *>(copy)) {
connect(src_footage, &Footage::ProxySettingsChanged, this,
[this, src_footage]() { SyncFootageProxySettings(src_footage); });
[this, src_footage]() {
SyncFootageProxySettings(src_footage);
});
SyncFootageProxySettings(src_footage);
}
}
@@ -279,14 +281,15 @@ void ProjectCopier::SyncFootageProxySettings(Footage *source)
Footage *copy = GetCopy(source);
if (!copy) {
qWarning() << "ProjectCopier::SyncFootageProxySettings: no copy for"
<< source->filename();
<< source->filename();
return;
}
qDebug() << "ProjectCopier::SyncFootageProxySettings:" << source->filename()
<< "enabled=" << source->proxy_enabled() << "->"
<< copy->proxy_enabled() << "state="
<< ProxyManager::ProxyStateToString(source->proxy_state());
qDebug()
<< "ProjectCopier::SyncFootageProxySettings:" << source->filename()
<< "enabled=" << source->proxy_enabled() << "->"
<< copy->proxy_enabled()
<< "state=" << ProxyManager::ProxyStateToString(source->proxy_state());
copy->SetProxy(source->proxy_path(), source->proxy_state(),
source->proxy_video_stream_index(),
+12 -10
View File
@@ -34,7 +34,8 @@
#include "texture.h"
// Forward declarations to keep the render core header lightweight
namespace olive {
namespace olive
{
class ColorTransformJob;
class Node;
}
@@ -57,17 +58,16 @@ public:
void DestroyTexture(Texture *texture);
virtual void BlitToTexture(QVariant shader, olive::AcceleratedJob& job,
olive::Texture *destination,
bool clear_destination = true)
virtual void BlitToTexture(QVariant shader, olive::AcceleratedJob &job,
olive::Texture *destination,
bool clear_destination = true)
{
Blit(shader, job, destination, destination->params(),
clear_destination);
}
void Blit(QVariant shader, olive::AcceleratedJob& job, olive::VideoParams params,
bool clear_destination = true)
void Blit(QVariant shader, olive::AcceleratedJob &job,
olive::VideoParams params, bool clear_destination = true)
{
Blit(shader, job, nullptr, params, clear_destination);
}
@@ -147,10 +147,12 @@ public:
*
* Default implementation is a no-op.
*/
virtual void DetachOutputTexture() {}
virtual void DetachOutputTexture()
{
}
protected:
virtual void Blit(QVariant shader, olive::AcceleratedJob& job,
virtual void Blit(QVariant shader, olive::AcceleratedJob &job,
olive::Texture *destination,
olive::VideoParams destination_params,
bool clear_destination) = 0;
@@ -164,7 +166,7 @@ protected:
virtual void DestroyInternal() = 0;
private:
std::atomic<bool> destroyed_{false};
std::atomic<bool> destroyed_{ false };
std::shared_ptr<RendererLifetime> lifetime_;
struct ColorContext {
struct LUT {
+14 -9
View File
@@ -78,24 +78,26 @@ QString RenderManager::BackendToString(Backend backend)
}
RenderManager::RenderManager(QObject *parent)
: backend_(BackendFromString(
OLIVE_CONFIG("GraphicsBackend").toString()))
: backend_(BackendFromString(OLIVE_CONFIG("GraphicsBackend").toString()))
, requested_backend_(backend_)
, aggressive_gc_(0)
, worker_pool_(nullptr)
{
if (backend_ == kVulkan) {
#ifndef OAK_ENABLE_DYNAMIC_RENDER_BACKEND
qWarning() << "Vulkan backend requested but dynamic render backend is not enabled. Falling back to OpenGL.";
qWarning()
<< "Vulkan backend requested but dynamic render backend is not enabled. Falling back to OpenGL.";
backend_ = kOpenGL;
#endif
}
if (backend_ == kOpenGL || backend_ == kVulkan) {
#ifdef OAK_ENABLE_DYNAMIC_RENDER_BACKEND
auto *dynamic_renderer = new DynamicRenderer(BackendToString(requested_backend_));
auto *dynamic_renderer =
new DynamicRenderer(BackendToString(requested_backend_));
if (!dynamic_renderer->Load()) {
qWarning() << "Failed to load dynamic render backend" << BackendToString(requested_backend_)
qWarning() << "Failed to load dynamic render backend"
<< BackendToString(requested_backend_)
<< ", falling back to OpenGL";
delete dynamic_renderer;
backend_ = kOpenGL;
@@ -104,7 +106,8 @@ RenderManager::RenderManager(QObject *parent)
context_ = dynamic_renderer;
// DynamicRenderer may internally fall back (e.g. Vulkan -> OpenGL).
// Synchronize RenderManager's view of the actual runtime backend.
Backend actual_backend = BackendFromString(dynamic_renderer->backend_name());
Backend actual_backend =
BackendFromString(dynamic_renderer->backend_name());
if (actual_backend != backend_) {
qWarning() << "Dynamic render backend fell back from"
<< BackendToString(backend_) << "to"
@@ -218,11 +221,13 @@ RenderTicketPtr RenderManager::RenderFrame(const RenderVideoParams &params)
if (worker_params.return_type == ReturnType::kNull) {
dry_run_thread_->AddTicket(ticket);
} else if (worker_pool_ && worker_pool_->SubmitFrame(ticket, worker_params)) {
} else if (worker_pool_ &&
worker_pool_->SubmitFrame(ticket, worker_params)) {
return ticket;
} else {
qWarning() << "RenderManager: worker pool unavailable, finishing ticket "
"without result";
qWarning()
<< "RenderManager: worker pool unavailable, finishing ticket "
"without result";
ticket->Finish();
}
+52 -50
View File
@@ -28,7 +28,6 @@
#include <QVector3D>
#include <QVector4D>
#include "audio/audioprocessor.h"
#include "node/block/clip/clip.h"
#include "node/block/transition/transition.h"
@@ -159,7 +158,6 @@ FramePtr RenderProcessor::GenerateFrame(TexturePtr texture,
QString::fromUtf8(output_color_transform->id()));
frame->set_video_params(display_params);
}
}
return frame;
@@ -173,7 +171,7 @@ void RenderProcessor::Run()
SetCancelPointer(ticket_->GetCancelAtom());
VideoParams params=ticket_->property("vparam").value<VideoParams>();
VideoParams params = ticket_->property("vparam").value<VideoParams>();
params.set_format(PixelFormat::F32);
SetCacheVideoParams(params);
SetCacheAudioParams(ticket_->property("aparam").value<AudioParams>());
@@ -416,27 +414,29 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination,
}
if (using_colorspace.isEmpty()) {
qWarning() << "RenderProcessor ProcessVideoFootage: no input colorspace available";
qWarning()
<< "RenderProcessor ProcessVideoFootage: no input colorspace available";
}
auto blit_color_managed = [&](const TexturePtr &unmanaged_texture,
const VideoParams &texture_params) {
const VideoParams &texture_params) {
if (!render_ctx_ || !unmanaged_texture || IsCancelled()) {
return;
}
// We convert to our rendering pixel format, since that will always be float-based which
// is necessary for correct color conversion
ColorProcessorPtr processor = ColorProcessor::Create(
color_manager, using_colorspace,
color_manager->GetReferenceColorSpace());
ColorProcessorPtr processor =
ColorProcessor::Create(color_manager, using_colorspace,
color_manager->GetReferenceColorSpace());
ColorTransformJob job;
job.SetColorProcessor(processor);
job.SetInputTexture(unmanaged_texture);
if (texture_params.channel_count() != VideoParams::kRGBAChannelCount ||
texture_params.colorspace() == color_manager->GetReferenceColorSpace()) {
texture_params.colorspace() ==
color_manager->GetReferenceColorSpace()) {
job.SetInputAlphaAssociation(kAlphaNone);
} else if (texture_params.premultiplied_alpha()) {
job.SetInputAlphaAssociation(kAlphaAssociated);
@@ -450,12 +450,14 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination,
render_ctx_->Flush();
};
auto *input_pool =
QtUtils::ValueToPtr<ipc::FrameSlotPool>(ticket_->property("ipc_input_pool"));
auto *input_pool = QtUtils::ValueToPtr<ipc::FrameSlotPool>(
ticket_->property("ipc_input_pool"));
int input_slot = -1;
const QVariantList input_slots = ticket_->property("ipc_input_slots").toList();
const QVariantList input_slots =
ticket_->property("ipc_input_slots").toList();
if (!input_slots.isEmpty()) {
const QVariant cursor_value = ticket_->property("ipc_input_slot_cursor");
const QVariant cursor_value =
ticket_->property("ipc_input_slot_cursor");
const int cursor = cursor_value.isValid() ? cursor_value.toInt() : 0;
if (cursor >= 0 && cursor < input_slots.size()) {
input_slot = input_slots.at(cursor).toInt();
@@ -467,25 +469,26 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination,
}
if (render_ctx_ && input_pool && input_slot >= 0) {
if (input_slot >= int(input_pool->slot_count())) {
qWarning() << "RenderProcessor received out-of-range IPC input frame slot"
<< input_slot;
qWarning()
<< "RenderProcessor received out-of-range IPC input frame slot"
<< input_slot;
return;
}
const ipc::FrameSlotMeta *meta = input_pool->Meta(uint32_t(input_slot));
if (meta && meta->width > 0 && meta->height > 0 && meta->data_size > 0 &&
if (meta && meta->width > 0 && meta->height > 0 &&
meta->data_size > 0 &&
meta->data_size <= int(input_pool->slot_data_bytes())) {
VideoParams input_params = stream_data;
input_params.set_width(meta->width);
input_params.set_height(meta->height);
input_params.set_format(PixelFormat::Format(meta->format));
input_params.set_channel_count(meta->channel_count);
// The decoder may leave depth at 0 for 2D frames, but the renderer
// needs depth >= 1 to compute image size and upload the texture.
if (input_params.depth() <= 0) {
input_params.set_depth(1);
}
// The decoder may leave depth at 0 for 2D frames, but the renderer
// needs depth >= 1 to compute image size and upload the texture.
if (input_params.depth() <= 0) {
input_params.set_depth(1);
}
// Prefer the colorspace that the main process used when decoding this
// frame. The FootageJob reconstructed in the worker may have stale or
@@ -498,9 +501,9 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination,
}
const int bytes_per_pixel = input_params.GetBytesPerPixel();
const int linesize_pixels = bytes_per_pixel > 0
? meta->linesize / bytes_per_pixel
: input_params.effective_width();
const int linesize_pixels = bytes_per_pixel > 0 ?
meta->linesize / bytes_per_pixel :
input_params.effective_width();
const void *slot_data = input_pool->SlotData(uint32_t(input_slot));
TexturePtr unmanaged_texture = render_ctx_->CreateTexture(
@@ -509,13 +512,15 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination,
blit_color_managed(unmanaged_texture, input_params);
return;
}
qWarning() << "RenderProcessor received invalid IPC input frame slot" << input_slot;
qWarning() << "RenderProcessor received invalid IPC input frame slot"
<< input_slot;
return;
}
if (!decoder_cache_) {
qWarning() << "RenderProcessor has no decoder cache or IPC input frame for"
<< stream->filename();
qWarning()
<< "RenderProcessor has no decoder cache or IPC input frame for"
<< stream->filename();
return;
}
@@ -523,15 +528,15 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination,
static_cast<RenderMode::Mode>(ticket_->property("mode").toInt()) ==
RenderMode::kOffline &&
stream->has_proxy() && QFileInfo::exists(stream->proxy_filename());
const QString decode_filename =
use_proxy ? stream->proxy_filename() : stream->filename();
const QString decoder_id =
use_proxy ? stream->proxy_decoder() : stream->decoder();
const int stream_index =
use_proxy ? stream->proxy_stream_index() : stream_data.stream_index();
const QString decode_filename = use_proxy ? stream->proxy_filename() :
stream->filename();
const QString decoder_id = use_proxy ? stream->proxy_decoder() :
stream->decoder();
const int stream_index = use_proxy ? stream->proxy_stream_index() :
stream_data.stream_index();
Decoder::CodecStream default_codec_stream(
decode_filename, stream_index, GetCurrentBlock());
Decoder::CodecStream default_codec_stream(decode_filename, stream_index,
GetCurrentBlock());
DecoderPtr decoder = nullptr;
@@ -553,8 +558,8 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination,
decode_filename, frame_number);
// Decoder will close automatically since it's a stream_ptr
decoder->Open(Decoder::CodecStream(
frame_filename, stream_index, GetCurrentBlock()));
decoder->Open(Decoder::CodecStream(frame_filename, stream_index,
GetCurrentBlock()));
}
break;
}
@@ -643,7 +648,8 @@ void RenderProcessor::ProcessShader(TexturePtr destination, const Node *node,
locker.unlock();
// Run shader
render_ctx_->BlitToTexture(shader, const_cast<ShaderJob&>(*job), destination.get());
render_ctx_->BlitToTexture(shader, const_cast<ShaderJob &>(*job),
destination.get());
}
void RenderProcessor::ProcessSamples(SampleBuffer &destination,
@@ -720,8 +726,7 @@ TexturePtr RenderProcessor::ProcessPluginJob(TexturePtr texture,
return destination;
}
auto *plugin_job =
dynamic_cast<plugin::PluginJob *>(texture->job());
auto *plugin_job = dynamic_cast<plugin::PluginJob *>(texture->job());
if (!plugin_job) {
return destination;
}
@@ -779,13 +784,8 @@ TexturePtr RenderProcessor::ProcessPluginJob(TexturePtr texture,
}
}
plugin_renderer.RenderPlugin(
src,
*plugin_job,
destination,
destination->params(),
true,
false);
plugin_renderer.RenderPlugin(src, *plugin_job, destination,
destination->params(), true, false);
return destination;
}
@@ -797,7 +797,8 @@ TexturePtr RenderProcessor::ProcessVideoCacheJob(const CacheJob *val)
// Auto-detect and discard black/empty cached frames (macOS TBDR artifact)
bool all_black = true;
if (frame->data() && frame->allocated_size() > 0) {
const uint8_t *pixels = reinterpret_cast<const uint8_t *>(frame->data());
const uint8_t *pixels =
reinterpret_cast<const uint8_t *>(frame->data());
size_t alloc_size = static_cast<size_t>(frame->allocated_size());
size_t check_bytes = std::min(alloc_size, size_t(4096));
for (size_t i = 0; i < check_bytes; ++i) {
@@ -808,7 +809,8 @@ TexturePtr RenderProcessor::ProcessVideoCacheJob(const CacheJob *val)
}
}
if (all_black) {
qWarning() << "[CACHE] Discarding black cached frame:" << val->GetFilename()
qWarning() << "[CACHE] Discarding black cached frame:"
<< val->GetFilename()
<< "time=" << frame->timestamp().toDouble()
<< "size=" << frame->allocated_size();
QFile::remove(val->GetFilename());
+2 -1
View File
@@ -32,7 +32,8 @@
namespace olive
{
namespace plugin {
namespace plugin
{
class PluginRenderer;
}
+152 -142
View File
@@ -62,8 +62,8 @@ struct FootageInput {
class FootageInputCollector : public NodeTraverser {
public:
QVector<FootageInput> Collect(const RenderManager::RenderVideoParams &params,
CancelAtom *cancel)
QVector<FootageInput>
Collect(const RenderManager::RenderVideoParams &params, CancelAtom *cancel)
{
SetCancelPointer(cancel);
VideoParams cache_params = params.video_params;
@@ -75,17 +75,15 @@ public:
if (cache_params.interlacing() != VideoParams::kInterlaceNone) {
frame_length /= 2;
}
NodeValueTable table = GenerateTable(params.node,
TimeRange(params.time,
params.time + frame_length));
NodeValueTable table = GenerateTable(
params.node, TimeRange(params.time, params.time + frame_length));
NodeValue texture = table.Get(NodeValue::kTexture);
ResolveJobs(texture);
if (cache_params.interlacing() != VideoParams::kInterlaceNone) {
NodeValueTable second_table =
GenerateTable(params.node,
TimeRange(params.time + frame_length,
params.time + frame_length * 2));
NodeValueTable second_table = GenerateTable(
params.node, TimeRange(params.time + frame_length,
params.time + frame_length * 2));
NodeValue second_texture = second_table.Get(NodeValue::kTexture);
ResolveJobs(second_texture);
}
@@ -94,13 +92,12 @@ public:
}
protected:
void ProcessVideoFootage(TexturePtr destination,
const FootageJob *stream,
void ProcessVideoFootage(TexturePtr destination, const FootageJob *stream,
const rational &input_time) override
{
Q_UNUSED(destination)
if (stream) {
inputs_.append({*stream, input_time});
inputs_.append({ *stream, input_time });
}
}
@@ -140,8 +137,7 @@ DecoderPtr ResolveDecoderFromCache(DecoderCache *decoder_cache,
}
FramePtr DecodeInputFrame(DecoderCache *decoder_cache,
const FootageInput &input,
CancelAtom *cancel)
const FootageInput &input, CancelAtom *cancel)
{
VideoParams stream_data = input.job.video_params();
QString filename = input.job.filename();
@@ -162,19 +158,17 @@ FramePtr DecodeInputFrame(DecoderCache *decoder_cache,
case VideoParams::kVideoTypeVideo:
case VideoParams::kVideoTypeStill:
decoder = ResolveDecoderFromCache(
decoder_cache,
decoder_id,
decoder_cache, decoder_id,
Decoder::CodecStream(filename, stream_index, nullptr));
break;
case VideoParams::kVideoTypeImageSequence: {
const int64_t frame_number =
stream_data.get_time_in_timebase_units(input.time);
filename = Decoder::TransformImageSequenceFileName(filename, frame_number);
filename =
Decoder::TransformImageSequenceFileName(filename, frame_number);
decoder = Decoder::CreateFromID(decoder_id);
if (decoder &&
!decoder->Open(Decoder::CodecStream(filename,
stream_index,
nullptr))) {
if (decoder && !decoder->Open(Decoder::CodecStream(
filename, stream_index, nullptr))) {
decoder = nullptr;
}
break;
@@ -188,9 +182,9 @@ FramePtr DecodeInputFrame(DecoderCache *decoder_cache,
Decoder::RetrieveVideoParams retrieve;
retrieve.divider = stream_data.divider();
retrieve.maximum_format = PixelFormat::U16;
retrieve.time = stream_data.video_type() == VideoParams::kVideoTypeVideo
? input.time
: Decoder::kAnyTimecode;
retrieve.time = stream_data.video_type() == VideoParams::kVideoTypeVideo ?
input.time :
Decoder::kAnyTimecode;
retrieve.cancelled = cancel;
retrieve.force_range = stream_data.color_range();
retrieve.src_interlacing = stream_data.interlacing();
@@ -207,15 +201,13 @@ FramePtr DecodeInputFrame(DecoderCache *decoder_cache,
frame_params.set_colorspace(stream_data.colorspace());
frame->set_video_params(frame_params);
}
}
return frame;
}
bool DecodeInputFrames(DecoderCache *decoder_cache,
const RenderManager::RenderVideoParams &params,
CancelAtom *cancel,
QVector<FramePtr> *frames)
CancelAtom *cancel, QVector<FramePtr> *frames)
{
frames->clear();
@@ -271,7 +263,8 @@ bool WriteControlMessage(QProcess *process, const QJsonObject &obj)
return false;
}
const QByteArray line = QJsonDocument(obj).toJson(QJsonDocument::Compact) + '\n';
const QByteArray line =
QJsonDocument(obj).toJson(QJsonDocument::Compact) + '\n';
const qint64 written = process->write(line);
if (written != line.size()) {
return false;
@@ -285,7 +278,8 @@ void TryWriteControlMessage(QProcess *process, const QJsonObject &obj)
return;
}
const QByteArray line = QJsonDocument(obj).toJson(QJsonDocument::Compact) + '\n';
const QByteArray line =
QJsonDocument(obj).toJson(QJsonDocument::Compact) + '\n';
process->write(line);
}
@@ -315,12 +309,14 @@ bool IsProcessAlive(qint64 process_id)
}
#if defined(Q_OS_WIN)
HANDLE handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, DWORD(process_id));
HANDLE handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE,
DWORD(process_id));
if (!handle) {
return false;
}
DWORD exit_code = 0;
const bool alive = GetExitCodeProcess(handle, &exit_code) && exit_code == STILL_ACTIVE;
const bool alive = GetExitCodeProcess(handle, &exit_code) &&
exit_code == STILL_ACTIVE;
CloseHandle(handle);
return alive;
#else
@@ -334,11 +330,11 @@ QString WorkerProcessDetails(const QProcess *process)
return QStringLiteral("worker process unavailable");
}
const QString exit_status =
process->exitStatus() == QProcess::CrashExit
? QStringLiteral("crash")
: QStringLiteral("normal");
return QStringLiteral("state=%1 exit_status=%2 exit_code=%3 process_error=%4 error=\"%5\"")
const QString exit_status = process->exitStatus() == QProcess::CrashExit ?
QStringLiteral("crash") :
QStringLiteral("normal");
return QStringLiteral(
"state=%1 exit_status=%2 exit_code=%3 process_error=%4 error=\"%5\"")
.arg(int(process->state()))
.arg(exit_status)
.arg(process->exitCode())
@@ -355,8 +351,9 @@ bool ReadControlMessage(QProcess *process, QJsonObject *out, QString *error,
*error = QStringLiteral("worker exited before response: %1")
.arg(WorkerProcessDetails(process));
} else {
*error = QStringLiteral("timeout waiting for worker response: %1")
.arg(WorkerProcessDetails(process));
*error =
QStringLiteral("timeout waiting for worker response: %1")
.arg(WorkerProcessDetails(process));
}
}
return false;
@@ -372,7 +369,8 @@ bool ReadControlMessage(QProcess *process, QJsonObject *out, QString *error,
const QJsonDocument doc = QJsonDocument::fromJson(line, &parse_error);
if (parse_error.error != QJsonParseError::NoError || !doc.isObject()) {
if (error) {
*error = QStringLiteral("worker emitted malformed control JSON");
*error =
QStringLiteral("worker emitted malformed control JSON");
}
return false;
}
@@ -394,11 +392,10 @@ bool ReadControlMessage(QProcess *process, QJsonObject *out, QString *error,
return false;
}
} // namespace
} // namespace
RenderWorkerPool::RenderWorkerPool(DecoderCache *decoder_cache,
const QString &gpu_backend,
QObject *parent)
const QString &gpu_backend, QObject *parent)
: QThread(parent)
, decoder_cache_(decoder_cache)
, gpu_backend_(gpu_backend)
@@ -410,8 +407,8 @@ RenderWorkerPool::~RenderWorkerPool()
Shutdown();
}
bool RenderWorkerPool::SubmitFrame(RenderTicketPtr ticket,
const RenderManager::RenderVideoParams &params)
bool RenderWorkerPool::SubmitFrame(
RenderTicketPtr ticket, const RenderManager::RenderVideoParams &params)
{
Job job(ticket, params);
if (!PrepareJob(ticket, params, &job)) {
@@ -505,13 +502,13 @@ void RenderWorkerPool::run()
active_jobs_.resize(worker_count);
}
std::vector<std::vector<std::unique_ptr<PooledWorker>>> local_pools(worker_count);
std::vector<std::vector<std::unique_ptr<PooledWorker>>> local_pools(
worker_count);
std::vector<std::thread> workers;
workers.reserve(size_t(worker_count));
for (int i = 0; i < worker_count; i++) {
workers.emplace_back([this, i, &local_pools]() {
WorkerLoop(i, &local_pools[i]);
});
workers.emplace_back(
[this, i, &local_pools]() { WorkerLoop(i, &local_pools[i]); });
}
for (std::thread &worker : workers) {
@@ -529,8 +526,7 @@ void RenderWorkerPool::run()
}
void RenderWorkerPool::WorkerLoop(
int worker_index,
std::vector<std::unique_ptr<PooledWorker>> *local_pool)
int worker_index, std::vector<std::unique_ptr<PooledWorker>> *local_pool)
{
while (true) {
mutex_.lock();
@@ -561,7 +557,8 @@ bool RenderWorkerPool::PrepareJob(RenderTicketPtr ticket,
Project *project = Project::GetProjectFromObject(params.node);
if (!project) {
qWarning() << "RenderWorkerPool could not resolve project for render node";
qWarning()
<< "RenderWorkerPool could not resolve project for render node";
return false;
}
@@ -582,12 +579,14 @@ bool RenderWorkerPool::PrepareJob(RenderTicketPtr ticket,
if (it != graph_cache_.end() && !project->is_modified()) {
graph_path = it->path;
AddGraphPathRefLocked(graph_path);
qDebug() << "RenderWorkerPool::PrepareJob: using cached graph snapshot"
<< graph_path;
qDebug()
<< "RenderWorkerPool::PrepareJob: using cached graph snapshot"
<< graph_path;
} else {
if (it != graph_cache_.end()) {
qDebug() << "RenderWorkerPool::PrepareJob: graph stale, rewriting"
<< project->is_modified();
qDebug()
<< "RenderWorkerPool::PrepareJob: graph stale, rewriting"
<< project->is_modified();
SetGraphPathCachedLocked(it->path, false);
graph_cache_.erase(it);
}
@@ -603,7 +602,7 @@ bool RenderWorkerPool::PrepareJob(RenderTicketPtr ticket,
project->set_modified(false);
}
locker.relock();
graph_cache_.insert(project_uuid, {graph_path});
graph_cache_.insert(project_uuid, { graph_path });
SetGraphPathCachedLocked(graph_path, true);
AddGraphPathRefLocked(graph_path);
}
@@ -625,34 +624,39 @@ bool RenderWorkerPool::WriteGraphSnapshot(Project *project, QString *path)
// still referenced them.
const QString graph_dir = QDir::tempPath();
QTemporaryFile file(QDir(graph_dir).filePath(QStringLiteral("oak-render-graph-XXXXXX.ove")));
QTemporaryFile file(QDir(graph_dir).filePath(
QStringLiteral("oak-render-graph-XXXXXX.ove")));
file.setAutoRemove(false);
if (!file.open()) {
qWarning() << "RenderWorkerPool failed to create graph snapshot temp file"
<< file.errorString();
qWarning()
<< "RenderWorkerPool failed to create graph snapshot temp file"
<< file.errorString();
return false;
}
QXmlStreamWriter writer(&file);
ProjectSerializer::SaveData data(ProjectSerializer::kProject, project, file.fileName());
const ProjectSerializer::Result result = ProjectSerializer::Save(&writer, data);
ProjectSerializer::SaveData data(ProjectSerializer::kProject, project,
file.fileName());
const ProjectSerializer::Result result =
ProjectSerializer::Save(&writer, data);
file.close();
if (result.code() != ProjectSerializer::kSuccess || writer.hasError()) {
qWarning() << "RenderWorkerPool failed to serialize graph snapshot"
<< result.GetDetails();
<< result.GetDetails();
QFile::remove(file.fileName());
return false;
}
qDebug() << "RenderWorkerPool wrote graph snapshot" << file.fileName()
<< "size" << QFileInfo(file.fileName()).size();
<< "size" << QFileInfo(file.fileName()).size();
*path = file.fileName();
return true;
}
bool RenderWorkerPool::IsSupported(const RenderManager::RenderVideoParams &params) const
bool RenderWorkerPool::IsSupported(
const RenderManager::RenderVideoParams &params) const
{
return params.node && params.return_type == RenderManager::kFrame &&
params.video_params.is_valid();
@@ -662,7 +666,8 @@ void RenderWorkerPool::ProcessJob(
const Job &job, int worker_index,
std::vector<std::unique_ptr<PooledWorker>> *local_pool)
{
const qint64 ticket_id = qint64(reinterpret_cast<quintptr>(job.ticket.get()));
const qint64 ticket_id =
qint64(reinterpret_cast<quintptr>(job.ticket.get()));
SetActiveWorker(worker_index, job.ticket, nullptr, ticket_id);
job.ticket->Start();
@@ -672,7 +677,8 @@ void RenderWorkerPool::ProcessJob(
return;
}
std::unique_ptr<PooledWorker> worker = AcquireWorker(local_pool, job.graph_path);
std::unique_ptr<PooledWorker> worker =
AcquireWorker(local_pool, job.graph_path);
if (!worker) {
qWarning() << "RenderWorkerPool failed to acquire worker for ticket"
<< ticket_id;
@@ -685,22 +691,24 @@ void RenderWorkerPool::ProcessJob(
if (attempt > 0) {
worker = AcquireWorker(local_pool, job.graph_path);
if (!worker) {
qWarning() << "RenderWorkerPool failed to acquire worker for retry"
<< ticket_id;
qWarning()
<< "RenderWorkerPool failed to acquire worker for retry"
<< ticket_id;
break;
}
}
const JobResult result = ProcessJobAttempt(job, worker_index, attempt,
worker.get());
const qint64 worker_pid = worker && worker->process
? worker->process->processId()
: 0;
const JobResult result =
ProcessJobAttempt(job, worker_index, attempt, worker.get());
const qint64 worker_pid =
worker && worker->process ? worker->process->processId() : 0;
const bool process_state_running = worker && worker->process &&
worker->process->state() == QProcess::Running;
worker->process->state() ==
QProcess::Running;
const bool os_alive = worker_pid > 0 && IsProcessAlive(worker_pid);
const bool worker_healthy = process_state_running || os_alive;
const bool keep_alive = (result == JobResult::kFinished) && worker_healthy;
const bool keep_alive = (result == JobResult::kFinished) &&
worker_healthy;
ReturnWorker(local_pool, std::move(worker), keep_alive);
worker.reset();
@@ -733,11 +741,12 @@ void RenderWorkerPool::ProcessJob(
ClearActiveWorker(worker_index, 0);
}
RenderWorkerPool::JobResult RenderWorkerPool::ProcessJobAttempt(
const Job &job, int worker_index, int attempt_index,
PooledWorker *worker)
RenderWorkerPool::JobResult
RenderWorkerPool::ProcessJobAttempt(const Job &job, int worker_index,
int attempt_index, PooledWorker *worker)
{
const qint64 ticket_id = qint64(reinterpret_cast<quintptr>(job.ticket.get()));
const qint64 ticket_id =
qint64(reinterpret_cast<quintptr>(job.ticket.get()));
if (job.ticket->IsCancelled()) {
return JobResult::kCancelled;
}
@@ -748,27 +757,25 @@ RenderWorkerPool::JobResult RenderWorkerPool::ProcessJobAttempt(
const qint64 worker_process_id = worker->process->processId();
const int output_width = job.params.force_size.width() > 0
? job.params.force_size.width()
: job.params.video_params.effective_width();
const int output_height = job.params.force_size.height() > 0
? job.params.force_size.height()
: job.params.video_params.effective_height();
const int output_width = job.params.force_size.width() > 0 ?
job.params.force_size.width() :
job.params.video_params.effective_width();
const int output_height = job.params.force_size.height() > 0 ?
job.params.force_size.height() :
job.params.video_params.effective_height();
const PixelFormat::Format output_format =
job.params.force_format != PixelFormat::INVALID
? PixelFormat::Format(job.params.force_format)
: PixelFormat::F32;
const int output_channels = job.params.force_channel_count > 0
? job.params.force_channel_count
: VideoParams::kRGBAChannelCount;
const int output_linesize =
Frame::generate_linesize_bytes(output_width, output_format,
output_channels);
job.params.force_format != PixelFormat::INVALID ?
PixelFormat::Format(job.params.force_format) :
PixelFormat::F32;
const int output_channels = job.params.force_channel_count > 0 ?
job.params.force_channel_count :
VideoParams::kRGBAChannelCount;
const int output_linesize = Frame::generate_linesize_bytes(
output_width, output_format, output_channels);
const size_t estimated_output_slot_bytes =
size_t(output_linesize) * size_t(output_height);
const int f32_rgba_linesize =
Frame::generate_linesize_bytes(output_width, PixelFormat::F32,
VideoParams::kRGBAChannelCount);
const int f32_rgba_linesize = Frame::generate_linesize_bytes(
output_width, PixelFormat::F32, VideoParams::kRGBAChannelCount);
const size_t f32_rgba_slot_bytes =
size_t(f32_rgba_linesize) * size_t(output_height);
const size_t output_slot_bytes =
@@ -795,10 +802,11 @@ RenderWorkerPool::JobResult RenderWorkerPool::ProcessJobAttempt(
QStringLiteral("-out");
}
if (!worker->output_region.Open(worker->output_shm_key,
output_region_bytes,
ipc::SharedMemoryRegion::kCreate)) {
qWarning() << "RenderWorkerPool failed to create output shared memory"
<< worker->output_region.error();
output_region_bytes,
ipc::SharedMemoryRegion::kCreate)) {
qWarning()
<< "RenderWorkerPool failed to create output shared memory"
<< worker->output_region.error();
return JobResult::kFatalFailure;
}
worker->output_pool = ipc::FrameSlotPool::Create(
@@ -823,17 +831,19 @@ RenderWorkerPool::JobResult RenderWorkerPool::ProcessJobAttempt(
ipc::SharedMemoryRegion::MakeKey(worker_process_id, 1) +
QStringLiteral("-in");
}
const size_t input_region_bytes =
ipc::FrameSlotPool::BytesNeeded(input_slot_count, input_slot_bytes);
const size_t input_region_bytes = ipc::FrameSlotPool::BytesNeeded(
input_slot_count, input_slot_bytes);
if (!worker->input_region.Open(worker->input_shm_key,
input_region_bytes,
ipc::SharedMemoryRegion::kCreate)) {
qWarning() << "RenderWorkerPool failed to create input shared memory"
<< worker->input_region.error();
input_region_bytes,
ipc::SharedMemoryRegion::kCreate)) {
qWarning()
<< "RenderWorkerPool failed to create input shared memory"
<< worker->input_region.error();
return JobResult::kFatalFailure;
}
worker->input_pool = ipc::FrameSlotPool::Create(
worker->input_region.data(), input_slot_count, input_slot_bytes);
worker->input_pool =
ipc::FrameSlotPool::Create(worker->input_region.data(),
input_slot_count, input_slot_bytes);
worker->input_slot_bytes = input_slot_bytes;
}
}
@@ -843,7 +853,8 @@ RenderWorkerPool::JobResult RenderWorkerPool::ProcessJobAttempt(
if (input_slot_count > 0) {
for (const FramePtr &frame : job.input_frames) {
if (frame->allocated_size() > int(worker->input_slot_bytes)) {
qWarning() << "RenderWorkerPool decoded input frame exceeds slot size";
qWarning()
<< "RenderWorkerPool decoded input frame exceeds slot size";
return JobResult::kFatalFailure;
}
@@ -869,9 +880,9 @@ RenderWorkerPool::JobResult RenderWorkerPool::ProcessJobAttempt(
const QString cs = frame->video_params().colorspace();
if (!cs.isEmpty()) {
const QByteArray cs_utf8 = cs.toUtf8();
const size_t copy_len = qMin(
static_cast<size_t>(cs_utf8.size()),
sizeof(meta->colorspace) - 1);
const size_t copy_len =
qMin(static_cast<size_t>(cs_utf8.size()),
sizeof(meta->colorspace) - 1);
memcpy(meta->colorspace, cs_utf8.constData(), copy_len);
meta->colorspace[copy_len] = '\0';
}
@@ -905,16 +916,16 @@ RenderWorkerPool::JobResult RenderWorkerPool::ProcessJobAttempt(
handshake.input_slots = input_slots.size();
handshake.output_slots = int(kOutputSlots);
handshake.slot_data_bytes = qint64(output_slot_bytes);
handshake.input_slot_data_bytes = input_slots.isEmpty()
? 0
: qint64(input_slot_bytes);
handshake.input_slot_data_bytes =
input_slots.isEmpty() ? 0 : qint64(input_slot_bytes);
if (!WriteControlMessage(worker->process, handshake.ToJson())) {
if (!job.ticket->IsCancelled()) {
qWarning() << "RenderWorkerPool failed to send shared-memory handshake";
qWarning()
<< "RenderWorkerPool failed to send shared-memory handshake";
}
ClearActiveWorker(worker_index, worker_process_id);
return job.ticket->IsCancelled() ? JobResult::kCancelled
: JobResult::kRetryableFailure;
return job.ticket->IsCancelled() ? JobResult::kCancelled :
JobResult::kRetryableFailure;
}
if (worker->loaded_graph_path != job.graph_path) {
@@ -929,12 +940,11 @@ RenderWorkerPool::JobResult RenderWorkerPool::ProcessJobAttempt(
<< error << worker->process->readAllStandardError();
}
ClearActiveWorker(worker_index, worker_process_id);
return job.ticket->IsCancelled() ? JobResult::kCancelled
: JobResult::kRetryableFailure;
return job.ticket->IsCancelled() ? JobResult::kCancelled :
JobResult::kRetryableFailure;
}
worker->loaded_graph_path = job.graph_path;
}
}
ipc::RenderFrameMsg render;
render.ticket_id = ticket_id;
render.node_uuid = job.node_token;
@@ -960,8 +970,8 @@ RenderWorkerPool::JobResult RenderWorkerPool::ProcessJobAttempt(
qWarning() << "RenderWorkerPool failed to send render_frame";
}
ClearActiveWorker(worker_index, worker_process_id);
return job.ticket->IsCancelled() ? JobResult::kCancelled
: JobResult::kRetryableFailure;
return job.ticket->IsCancelled() ? JobResult::kCancelled :
JobResult::kRetryableFailure;
}
QString error;
@@ -974,8 +984,8 @@ RenderWorkerPool::JobResult RenderWorkerPool::ProcessJobAttempt(
<< error << worker->process->readAllStandardError();
}
ClearActiveWorker(worker_index, worker_process_id);
return job.ticket->IsCancelled() ? JobResult::kCancelled
: JobResult::kRetryableFailure;
return job.ticket->IsCancelled() ? JobResult::kCancelled :
JobResult::kRetryableFailure;
}
if (ipc::FrameReadyMsg::FromJson(response, &ready)) {
@@ -1068,8 +1078,8 @@ std::unique_ptr<RenderWorkerPool::PooledWorker> RenderWorkerPool::AcquireWorker(
local_pool->erase(local_pool->begin() + i);
continue;
}
const bool candidate_state_running =
candidate->process->state() == QProcess::Running;
const bool candidate_state_running = candidate->process->state() ==
QProcess::Running;
const bool candidate_os_alive =
IsProcessAlive(candidate->process->processId());
if (!candidate_state_running && !candidate_os_alive) {
@@ -1085,7 +1095,8 @@ std::unique_ptr<RenderWorkerPool::PooledWorker> RenderWorkerPool::AcquireWorker(
if (best_index < 0 ||
(!candidate->loaded_graph_path.isEmpty() &&
candidate->loaded_graph_path == graph_path &&
((*local_pool)[size_t(best_index)]->loaded_graph_path != graph_path))) {
((*local_pool)[size_t(best_index)]->loaded_graph_path !=
graph_path))) {
best_index = int(i);
}
++i;
@@ -1100,16 +1111,16 @@ std::unique_ptr<RenderWorkerPool::PooledWorker> RenderWorkerPool::AcquireWorker(
return worker;
}
// No idle worker available: start a new one.
auto *process = new QProcess();
process->setProgram(WorkerProgramPath());
process->setArguments({QStringLiteral("--backend"), gpu_backend_});
process->setArguments({ QStringLiteral("--backend"), gpu_backend_ });
const QString worker_stderr_path = QDir(QDir::tempPath()).filePath(
QStringLiteral("oak-render-worker-%1-%2.stderr.log")
.arg(QCoreApplication::applicationPid())
.arg(QDateTime::currentMSecsSinceEpoch()));
const QString worker_stderr_path =
QDir(QDir::tempPath())
.filePath(QStringLiteral("oak-render-worker-%1-%2.stderr.log")
.arg(QCoreApplication::applicationPid())
.arg(QDateTime::currentMSecsSinceEpoch()));
process->setStandardErrorFile(worker_stderr_path);
process->start();
@@ -1140,8 +1151,7 @@ std::unique_ptr<RenderWorkerPool::PooledWorker> RenderWorkerPool::AcquireWorker(
void RenderWorkerPool::ReturnWorker(
std::vector<std::unique_ptr<PooledWorker>> *local_pool,
std::unique_ptr<PooledWorker> worker,
bool keep_alive)
std::unique_ptr<PooledWorker> worker, bool keep_alive)
{
if (!worker || !worker->process) {
return;
@@ -1216,8 +1226,7 @@ void RenderWorkerPool::FinishWithFrame(RenderTicketPtr ticket,
}
VideoParams params(meta->width, meta->height,
PixelFormat::Format(meta->format),
meta->channel_count);
PixelFormat::Format(meta->format), meta->channel_count);
FramePtr frame = Frame::Create();
frame->set_timestamp(rational(int(meta->time_num), int(meta->time_den)));
frame->set_video_params(params);
@@ -1281,7 +1290,8 @@ void RenderWorkerPool::SetGraphPathCached(const QString &path, bool cached)
SetGraphPathCachedLocked(path, cached);
}
void RenderWorkerPool::SetGraphPathCachedLocked(const QString &path, bool cached)
void RenderWorkerPool::SetGraphPathCachedLocked(const QString &path,
bool cached)
{
if (path.isEmpty()) {
return;
@@ -1296,4 +1306,4 @@ void RenderWorkerPool::SetGraphPathCachedLocked(const QString &path, bool cached
}
}
} // namespace olive
} // namespace olive
+7 -8
View File
@@ -114,8 +114,7 @@ private:
};
bool PrepareJob(RenderTicketPtr ticket,
const RenderManager::RenderVideoParams &params,
Job *job);
const RenderManager::RenderVideoParams &params, Job *job);
bool WriteGraphSnapshot(Project *project, QString *path);
bool IsSupported(const RenderManager::RenderVideoParams &params) const;
@@ -124,8 +123,7 @@ private:
void ProcessJob(const Job &job, int worker_index,
std::vector<std::unique_ptr<PooledWorker>> *local_pool);
JobResult ProcessJobAttempt(const Job &job, int worker_index,
int attempt_index,
PooledWorker *worker);
int attempt_index, PooledWorker *worker);
void FinishWithFrame(RenderTicketPtr ticket, const ipc::FrameSlotPool &pool,
uint32_t slot);
void CleanupGraphFile(const QString &path);
@@ -141,13 +139,14 @@ private:
void ClearActiveWorker(int worker_index, qint64 process_id);
int WorkerCount() const;
std::unique_ptr<PooledWorker> AcquireWorker(
std::vector<std::unique_ptr<PooledWorker>> *local_pool,
const QString &graph_path);
std::unique_ptr<PooledWorker>
AcquireWorker(std::vector<std::unique_ptr<PooledWorker>> *local_pool,
const QString &graph_path);
void ReturnWorker(std::vector<std::unique_ptr<PooledWorker>> *local_pool,
std::unique_ptr<PooledWorker> worker, bool keep_alive);
void ShutdownWorker(PooledWorker *worker);
void ShutdownLocalPool(std::vector<std::unique_ptr<PooledWorker>> *local_pool);
void
ShutdownLocalPool(std::vector<std::unique_ptr<PooledWorker>> *local_pool);
void ClearGraphCache();
DecoderCache *decoder_cache_;
+6 -4
View File
@@ -36,7 +36,7 @@ namespace olive
class AcceleratedJob;
class Renderer;
struct RendererLifetime {
std::atomic<bool> alive{true};
std::atomic<bool> alive{ true };
};
class Texture;
@@ -162,16 +162,18 @@ public:
}
void handleFrame(AVFramePtr ptr)
{
frame_=ptr;
frame_ = ptr;
}
AVFramePtr frame(){
AVFramePtr frame()
{
return frame_;
}
private:
bool IsRendererAlive() const
{
return renderer_ &&
(!renderer_lifetime_ || renderer_lifetime_->alive.load());
(!renderer_lifetime_ || renderer_lifetime_->alive.load());
}
Renderer *renderer_;
+2 -2
View File
@@ -259,8 +259,8 @@ QString VideoParams::GetFormatName(PixelFormat format)
break;
}
return QCoreApplication::translate("VideoParams", "Unknown (0x%1)")
.arg(static_cast<int>(format), 0, 16);
return QCoreApplication::translate("VideoParams", "Unknown (0x%1)")
.arg(static_cast<int>(format), 0, 16);
}
int VideoParams::GetDividerForTargetResolution(int src_width, int src_height,
+75 -57
View File
@@ -11,7 +11,8 @@
#include "render/videoparams.h"
#include "render/vulkan/vulkanrenderer.h"
namespace {
namespace
{
class BackendVulkanRenderer : public olive::VulkanRenderer {
public:
@@ -38,38 +39,42 @@ const QVariant &VariantRef(const void *variant)
} // namespace
// Creates the Vulkan backend object and returns it as an opaque C handle.
OAK_RENDER_BACKEND_EXPORT OakRenderBackendHandle oak_renderer_create(void *parent)
OAK_RENDER_BACKEND_EXPORT OakRenderBackendHandle
oak_renderer_create(void *parent)
{
return new BackendVulkanRenderer(static_cast<QObject *>(parent));
}
// Destroys the opaque backend object created by oak_renderer_create().
OAK_RENDER_BACKEND_EXPORT void oak_renderer_destroy(OakRenderBackendHandle handle)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_destroy(OakRenderBackendHandle handle)
{
delete Renderer(handle);
}
// Reports Vulkan backend capabilities and runtime availability status.
OAK_RENDER_BACKEND_EXPORT bool oak_renderer_get_info(
OakRenderBackendHandle handle, OakRenderBackendInfo *out_info)
OAK_RENDER_BACKEND_EXPORT bool
oak_renderer_get_info(OakRenderBackendHandle handle,
OakRenderBackendInfo *out_info)
{
if (!handle || !out_info) {
return false;
}
out_info->abi_version = 1;
out_info->kind = OAK_RENDER_BACKEND_VULKAN;
out_info->capabilities = OAK_RENDER_BACKEND_CAP_TEXTURES |
OAK_RENDER_BACKEND_CAP_SHADERS | OAK_RENDER_BACKEND_CAP_BLIT |
OAK_RENDER_BACKEND_CAP_READBACK;
out_info->capabilities =
OAK_RENDER_BACKEND_CAP_TEXTURES | OAK_RENDER_BACKEND_CAP_SHADERS |
OAK_RENDER_BACKEND_CAP_BLIT | OAK_RENDER_BACKEND_CAP_READBACK;
out_info->name = "vulkan";
out_info->status = Renderer(handle)->IsAvailable() ? "available" : "unavailable";
out_info->status = Renderer(handle)->IsAvailable() ? "available" :
"unavailable";
return true;
}
// Probes runtime availability by trying Init() once; this lets missing ICDs or
// unusable drivers fall back before normal rendering starts.
OAK_RENDER_BACKEND_EXPORT bool oak_renderer_is_available(
OakRenderBackendHandle handle)
OAK_RENDER_BACKEND_EXPORT bool
oak_renderer_is_available(OakRenderBackendHandle handle)
{
auto *r = Renderer(handle);
if (!r || r->IsAvailable()) {
@@ -89,41 +94,41 @@ OAK_RENDER_BACKEND_EXPORT bool oak_renderer_init(OakRenderBackendHandle handle)
}
// Vulkan does not use a QOpenGLContext; the argument is accepted for ABI parity.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_init_with_context(
OakRenderBackendHandle handle, void *context)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_init_with_context(OakRenderBackendHandle handle, void *context)
{
Q_UNUSED(context)
Renderer(handle)->Init();
}
// Creates reusable Vulkan resources after device initialization.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_post_init(
OakRenderBackendHandle handle)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_post_init(OakRenderBackendHandle handle)
{
Renderer(handle)->PostInit();
}
// Reserved for API symmetry; Vulkan cleanup is handled by destroy_internal.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_post_destroy(
OakRenderBackendHandle handle)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_post_destroy(OakRenderBackendHandle handle)
{
Renderer(handle)->PostDestroy();
}
// Releases all Vulkan resources owned by the renderer.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_destroy_internal(
OakRenderBackendHandle handle)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_destroy_internal(OakRenderBackendHandle handle)
{
Renderer(handle)->DestroyInternal();
}
// Clears a Vulkan texture destination.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_clear_destination(
OakRenderBackendHandle handle, void *texture, double r, double g, double b,
double a)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_clear_destination(OakRenderBackendHandle handle, void *texture,
double r, double g, double b, double a)
{
Renderer(handle)->ClearDestination(static_cast<olive::Texture *>(texture),
r, g, b, a);
r, g, b, a);
}
// Creates a Vulkan texture and writes its QVariant handle to out_variant.
@@ -131,51 +136,58 @@ OAK_RENDER_BACKEND_EXPORT void oak_renderer_create_native_texture(
OakRenderBackendHandle handle, int width, int height, int depth, int format,
int channel_count, const void *data, int linesize, void *out_variant)
{
*static_cast<QVariant *>(out_variant) = Renderer(handle)->CreateNativeTexture(
width, height, depth, static_cast<olive::PixelFormat::Format>(format),
channel_count, data, linesize);
*static_cast<QVariant *>(out_variant) =
Renderer(handle)->CreateNativeTexture(
width, height, depth,
static_cast<olive::PixelFormat::Format>(format), channel_count,
data, linesize);
}
// Destroys a Vulkan texture represented by a QVariant handle.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_destroy_native_texture(
OakRenderBackendHandle handle, const void *variant)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_destroy_native_texture(OakRenderBackendHandle handle,
const void *variant)
{
Renderer(handle)->DestroyNativeTexture(VariantRef(variant));
}
// Compiles a Vulkan shader and returns its QVariant handle.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_create_native_shader(
OakRenderBackendHandle handle, const void *shader_code, void *out_variant)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_create_native_shader(OakRenderBackendHandle handle,
const void *shader_code, void *out_variant)
{
*static_cast<QVariant *>(out_variant) = Renderer(handle)->CreateNativeShader(
*static_cast<const olive::ShaderCode *>(shader_code));
*static_cast<QVariant *>(out_variant) =
Renderer(handle)->CreateNativeShader(
*static_cast<const olive::ShaderCode *>(shader_code));
}
// Destroys a Vulkan shader represented by a QVariant handle.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_destroy_native_shader(
OakRenderBackendHandle handle, const void *variant)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_destroy_native_shader(OakRenderBackendHandle handle,
const void *variant)
{
Renderer(handle)->DestroyNativeShader(VariantRef(variant));
}
// Uploads CPU pixel data into a Vulkan texture.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_upload_to_texture(
OakRenderBackendHandle handle, const void *variant, const void *video_params,
const void *data, int linesize)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_upload_to_texture(OakRenderBackendHandle handle,
const void *variant, const void *video_params,
const void *data, int linesize)
{
Renderer(handle)->UploadToTexture(
VariantRef(variant), *static_cast<const olive::VideoParams *>(video_params),
data, linesize);
VariantRef(variant),
*static_cast<const olive::VideoParams *>(video_params), data, linesize);
}
// Downloads a Vulkan texture to CPU memory.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_download_from_texture(
OakRenderBackendHandle handle, const void *variant, const void *video_params,
void *data, int linesize)
OakRenderBackendHandle handle, const void *variant,
const void *video_params, void *data, int linesize)
{
Renderer(handle)->DownloadFromTexture(
VariantRef(variant), *static_cast<const olive::VideoParams *>(video_params),
data, linesize);
VariantRef(variant),
*static_cast<const olive::VideoParams *>(video_params), data, linesize);
}
// Waits for all queued Vulkan work to finish.
@@ -185,18 +197,23 @@ OAK_RENDER_BACKEND_EXPORT void oak_renderer_flush(OakRenderBackendHandle handle)
}
// Reads one pixel from a Vulkan texture.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_get_pixel_from_texture(
OakRenderBackendHandle handle, void *texture, const void *point,
void *out_color)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_get_pixel_from_texture(OakRenderBackendHandle handle,
void *texture, const void *point,
void *out_color)
{
*static_cast<olive::Color *>(out_color) = Renderer(handle)->GetPixelFromTexture(
static_cast<olive::Texture *>(texture), *static_cast<const QPointF *>(point));
*static_cast<olive::Color *>(out_color) =
Renderer(handle)->GetPixelFromTexture(
static_cast<olive::Texture *>(texture),
*static_cast<const QPointF *>(point));
}
// Executes a shader blit through the wrapped Vulkan renderer.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_blit(
OakRenderBackendHandle handle, const void *shader, void *job,
void *destination, const void *destination_params, bool clear_destination)
OAK_RENDER_BACKEND_EXPORT void oak_renderer_blit(OakRenderBackendHandle handle,
const void *shader, void *job,
void *destination,
const void *destination_params,
bool clear_destination)
{
Renderer(handle)->Blit(
VariantRef(shader), *static_cast<olive::AcceleratedJob *>(job),
@@ -206,16 +223,17 @@ OAK_RENDER_BACKEND_EXPORT void oak_renderer_blit(
}
// Vulkan has no OpenGL context; return null so callers avoid GL-only paths.
OAK_RENDER_BACKEND_EXPORT void *oak_renderer_opengl_context(
OakRenderBackendHandle handle)
OAK_RENDER_BACKEND_EXPORT void *
oak_renderer_opengl_context(OakRenderBackendHandle handle)
{
Q_UNUSED(handle)
return nullptr;
}
// OFX OpenGL output attachment is unsupported in Vulkan and intentionally no-op.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_attach_output_texture(
OakRenderBackendHandle handle, const void *texture_id)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_attach_output_texture(OakRenderBackendHandle handle,
const void *texture_id)
{
Q_UNUSED(handle)
Q_UNUSED(texture_id)
@@ -223,8 +241,8 @@ OAK_RENDER_BACKEND_EXPORT void oak_renderer_attach_output_texture(
}
// OFX OpenGL output detachment is unsupported in Vulkan and intentionally no-op.
OAK_RENDER_BACKEND_EXPORT void oak_renderer_detach_output_texture(
OakRenderBackendHandle handle)
OAK_RENDER_BACKEND_EXPORT void
oak_renderer_detach_output_texture(OakRenderBackendHandle handle)
{
Q_UNUSED(handle)
// Vulkan does not support OFX OpenGL render output attachment.
File diff suppressed because it is too large Load Diff
+27 -23
View File
@@ -51,8 +51,8 @@ public:
// Clears either a texture render target or the currently bound output target.
virtual void ClearDestination(olive::Texture *texture = nullptr,
double r = 0.0, double g = 0.0,
double b = 0.0, double a = 0.0) override;
double r = 0.0, double g = 0.0,
double b = 0.0, double a = 0.0) override;
// Compiles GLSL to SPIR-V, creates shader modules, and prepares descriptor
// metadata for later blits.
@@ -63,12 +63,12 @@ public:
// Uploads CPU pixel data to a Vulkan image via a staging buffer.
virtual void UploadToTexture(const QVariant &handle,
const VideoParams &params, const void *data,
int linesize) override;
const VideoParams &params, const void *data,
int linesize) override;
// Downloads a Vulkan image to CPU memory via a staging buffer.
virtual void DownloadFromTexture(const QVariant &handle,
const VideoParams &params, void *data,
int linesize) override;
const VideoParams &params, void *data,
int linesize) override;
// Waits for outstanding device work to complete.
virtual void Flush() override;
@@ -80,7 +80,7 @@ public:
// Reads a single texture pixel using a one-pixel transfer readback.
virtual Color GetPixelFromTexture(olive::Texture *texture,
const QPointF &pt) override;
const QPointF &pt) override;
bool IsAvailable() const
{
@@ -90,14 +90,15 @@ public:
protected:
// Runs one or more fullscreen shader passes into the destination texture.
virtual void Blit(QVariant shader, olive::AcceleratedJob &job,
olive::Texture *destination, VideoParams destination_params,
bool clear_destination) override;
olive::Texture *destination,
VideoParams destination_params,
bool clear_destination) override;
// Creates a Vulkan image/view/memory bundle and optionally uploads initial
// pixel data.
virtual QVariant CreateNativeTexture(int width, int height, int depth,
PixelFormat format, int channel_count,
const void *data = nullptr,
int linesize = 0) override;
PixelFormat format, int channel_count,
const void *data = nullptr,
int linesize = 0) override;
// Releases a Vulkan texture bundle.
virtual void DestroyNativeTexture(QVariant texture) override;
// Releases all Vulkan device resources owned by this renderer.
@@ -172,10 +173,10 @@ private:
float GetFormatMaxAlpha(PixelFormat format) const;
// Repackages tightly packed pixels when the requested CPU channel count
// differs from the selected GPU format channel count.
void CopyPixelsWithChannelConversion(const void *src, void *dst,
int width, int height, int depth,
int src_channels, int dst_channels,
PixelFormat format) const;
void CopyPixelsWithChannelConversion(const void *src, void *dst, int width,
int height, int depth,
int src_channels, int dst_channels,
PixelFormat format) const;
// Rounds a size up to the requested alignment.
VkDeviceSize AlignSize(VkDeviceSize size, VkDeviceSize alignment) const;
@@ -187,11 +188,13 @@ private:
bool CompileGlslToSpv(const QString &glsl, VkShaderStageFlagBits stage,
QByteArray *out_spv);
// Rewrites an Oak GLSL shader into Vulkan-compatible GLSL.
QString ConvertGlslToVulkan(const QString &glsl, VkShaderStageFlagBits stage);
QString ConvertGlslToVulkan(const QString &glsl,
VkShaderStageFlagBits stage);
// Ensures a shader declares a Vulkan-compatible GLSL version.
QString EnsureGlslVersion450(const QString &glsl) const;
// Extracts uniforms and sampler names from GLSL declarations.
void ExtractUniforms(const QString &glsl, QVector<UniformInfo> *out_uniforms,
void ExtractUniforms(const QString &glsl,
QVector<UniformInfo> *out_uniforms,
QVector<QString> *out_samplers) const;
// Computes std140 offsets and total UBO size for extracted uniforms.
void ComputeUniformLayout(QVector<UniformInfo> *uniforms) const;
@@ -199,9 +202,10 @@ private:
QString BuildUboBlock(const QVector<UniformInfo> &uniforms) const;
// Rewrites standalone uniforms and samplers into explicit UBO/sampler
// bindings accepted by Vulkan GLSL.
QString RewriteShaderWithUbo(const QString &glsl,
const QVector<UniformInfo> &all_uniforms,
const QHash<QString, int> &sampler_bindings) const;
QString
RewriteShaderWithUbo(const QString &glsl,
const QVector<UniformInfo> &all_uniforms,
const QHash<QString, int> &sampler_bindings) const;
// Returns std140 storage size for a supported GLSL type.
VkDeviceSize GetStd140Size(const QString &type) const;
// Returns std140 alignment for a supported GLSL type.
@@ -225,8 +229,8 @@ private:
void BlitPass(VulkanShader *shader, VulkanTexture *dest_tex,
const QVector<TextureBinding> &bindings,
const QByteArray &ubo_data,
const VideoParams &destination_params,
bool clear_destination, int iteration);
const VideoParams &destination_params, bool clear_destination,
int iteration);
VkInstance instance_ = VK_NULL_HANDLE;
VkDebugUtilsMessengerEXT debug_messenger_ = VK_NULL_HANDLE;
+146 -96
View File
@@ -110,7 +110,6 @@ public:
bool InitializeRuntime()
{
// Create a minimal Core instance so that code paths calling Core::instance()
// (e.g. ViewerOutput::data for timecode display) do not dereference null.
// The worker is short-lived; leaking this on exit is harmless.
@@ -141,7 +140,8 @@ public:
QJsonObject handshake = hs.ToJson();
QOpenGLContext *ctx = nullptr;
#ifdef OAK_ENABLE_DYNAMIC_RENDER_BACKEND
if (auto *dynamic_renderer = dynamic_cast<olive::DynamicRenderer *>(renderer_)) {
if (auto *dynamic_renderer =
dynamic_cast<olive::DynamicRenderer *>(renderer_)) {
ctx = dynamic_renderer->OpenGLContext();
} else
#endif
@@ -164,7 +164,8 @@ public:
if (type == QLatin1String(olive::ipc::msgtype::kHandshake)) {
olive::ipc::HandshakeMsg hs;
if (!olive::ipc::HandshakeMsg::FromJson(message, &hs)) {
return Write(ErrorMessage(QStringLiteral("invalid handshake message")));
return Write(
ErrorMessage(QStringLiteral("invalid handshake message")));
}
return AttachOutputPool(hs);
}
@@ -172,7 +173,8 @@ public:
if (type == QLatin1String(olive::ipc::msgtype::kLoadGraph)) {
olive::ipc::LoadGraphMsg load;
if (!olive::ipc::LoadGraphMsg::FromJson(message, &load)) {
return Write(ErrorMessage(QStringLiteral("invalid load_graph message")));
return Write(
ErrorMessage(QStringLiteral("invalid load_graph message")));
}
return LoadGraph(load.path);
}
@@ -180,7 +182,8 @@ public:
if (type == QLatin1String(olive::ipc::msgtype::kRenderFrame)) {
olive::ipc::RenderFrameMsg render;
if (!olive::ipc::RenderFrameMsg::FromJson(message, &render)) {
return Write(ErrorMessage(QStringLiteral("invalid render_frame message")));
return Write(ErrorMessage(
QStringLiteral("invalid render_frame message")));
}
return RenderFrame(render);
}
@@ -195,7 +198,8 @@ public:
return true;
}
return Write(ErrorMessage(QStringLiteral("unknown message type: %1").arg(type)));
return Write(
ErrorMessage(QStringLiteral("unknown message type: %1").arg(type)));
}
bool shutdown_requested() const
@@ -214,48 +218,58 @@ private:
bool AttachOutputPool(const olive::ipc::HandshakeMsg &hs)
{
if (hs.protocol_version != kProtocolVersion) {
return Write(ErrorMessage(QStringLiteral("unsupported protocol version %1")
.arg(hs.protocol_version)));
return Write(
ErrorMessage(QStringLiteral("unsupported protocol version %1")
.arg(hs.protocol_version)));
}
if (hs.shm_key.isEmpty() || hs.output_slots <= 0 || hs.slot_data_bytes <= 0) {
return Write(ErrorMessage(QStringLiteral("handshake missing output shared-memory geometry")));
if (hs.shm_key.isEmpty() || hs.output_slots <= 0 ||
hs.slot_data_bytes <= 0) {
return Write(ErrorMessage(QStringLiteral(
"handshake missing output shared-memory geometry")));
}
const size_t bytes = olive::ipc::FrameSlotPool::BytesNeeded(
uint32_t(hs.output_slots), size_t(hs.slot_data_bytes));
if (!output_region_.Open(hs.shm_key, bytes, olive::ipc::SharedMemoryRegion::kAttach)) {
return Write(ErrorMessage(QStringLiteral("failed to attach shared memory: %1")
.arg(output_region_.error())));
if (!output_region_.Open(hs.shm_key, bytes,
olive::ipc::SharedMemoryRegion::kAttach)) {
return Write(ErrorMessage(
QStringLiteral("failed to attach shared memory: %1")
.arg(output_region_.error())));
}
output_pool_ = olive::ipc::FrameSlotPool::Attach(output_region_.data());
if (!output_pool_->IsValid()) {
output_region_.Close();
output_pool_.reset();
return Write(ErrorMessage(QStringLiteral("shared memory does not contain a frame slot pool")));
return Write(ErrorMessage(QStringLiteral(
"shared memory does not contain a frame slot pool")));
}
input_pool_.reset();
input_region_.Close();
if (hs.input_slots > 0) {
if (hs.input_shm_key.isEmpty() || hs.input_slot_data_bytes <= 0) {
return Write(ErrorMessage(QStringLiteral("handshake missing input shared-memory geometry")));
return Write(ErrorMessage(QStringLiteral(
"handshake missing input shared-memory geometry")));
}
const size_t input_bytes = olive::ipc::FrameSlotPool::BytesNeeded(
uint32_t(hs.input_slots), size_t(hs.input_slot_data_bytes));
if (!input_region_.Open(hs.input_shm_key, input_bytes,
olive::ipc::SharedMemoryRegion::kAttach)) {
return Write(ErrorMessage(QStringLiteral("failed to attach input shared memory: %1")
.arg(input_region_.error())));
return Write(ErrorMessage(
QStringLiteral("failed to attach input shared memory: %1")
.arg(input_region_.error())));
}
input_pool_ = olive::ipc::FrameSlotPool::Attach(input_region_.data());
input_pool_ =
olive::ipc::FrameSlotPool::Attach(input_region_.data());
if (!input_pool_->IsValid()) {
input_region_.Close();
input_pool_.reset();
return Write(ErrorMessage(QStringLiteral("input shared memory does not contain a frame slot pool")));
return Write(ErrorMessage(QStringLiteral(
"input shared memory does not contain a frame slot pool")));
}
}
@@ -267,17 +281,23 @@ private:
{
QFileInfo fi(path);
if (!fi.exists()) {
LogError(QStringLiteral("LoadGraph: graph file does not exist: %1").arg(path));
return Write(ErrorMessage(QStringLiteral("graph file does not exist: %1").arg(path)));
LogError(
QStringLiteral("LoadGraph: graph file does not exist: %1")
.arg(path));
return Write(ErrorMessage(
QStringLiteral("graph file does not exist: %1").arg(path)));
}
if (fi.size() == 0) {
LogError(QStringLiteral("LoadGraph: graph file is empty: %1").arg(path));
return Write(ErrorMessage(QStringLiteral("graph file is empty: %1").arg(path)));
LogError(QStringLiteral("LoadGraph: graph file is empty: %1")
.arg(path));
return Write(ErrorMessage(
QStringLiteral("graph file is empty: %1").arg(path)));
}
LogError(QStringLiteral("LoadGraph: loading %1 (%2 bytes, readable=%3)")
.arg(path)
.arg(fi.size())
.arg(fi.isReadable()));
LogError(
QStringLiteral("LoadGraph: loading %1 (%2 bytes, readable=%3)")
.arg(path)
.arg(fi.size())
.arg(fi.isReadable()));
}
auto loaded = std::make_unique<olive::Project>();
@@ -286,10 +306,12 @@ private:
// Initialize() first triggers Q_ASSERT(!root_) in Project::Load.
olive::ProjectSerializer::Result result =
olive::ProjectSerializer::Load(loaded.get(), path, olive::ProjectSerializer::kProject);
olive::ProjectSerializer::Load(loaded.get(), path,
olive::ProjectSerializer::kProject);
if (result != olive::ProjectSerializer::kSuccess) {
return Write(ErrorMessage(QStringLiteral("failed to load graph %1: %2")
.arg(path, result.GetDetails())));
return Write(
ErrorMessage(QStringLiteral("failed to load graph %1: %2")
.arg(path, result.GetDetails())));
}
project_ = std::move(loaded);
@@ -297,12 +319,15 @@ private:
color_processor_cache_.clear();
const auto &data = result.GetLoadData();
for (auto it = data.node_ptrs.cbegin(); it != data.node_ptrs.cend(); ++it) {
for (auto it = data.node_ptrs.cbegin(); it != data.node_ptrs.cend();
++it) {
node_by_token_.insert(QString::number(it.key()), it.value());
}
for (auto it = data.node_uuids.cbegin(); it != data.node_uuids.cend(); ++it) {
for (auto it = data.node_uuids.cbegin(); it != data.node_uuids.cend();
++it) {
node_by_token_.insert(it.value().toString(), it.key());
node_by_token_.insert(it.value().toString(QUuid::WithoutBraces), it.key());
node_by_token_.insert(it.value().toString(QUuid::WithoutBraces),
it.key());
}
QJsonObject ack;
@@ -329,29 +354,36 @@ private:
bool RenderFrame(const olive::ipc::RenderFrameMsg &message)
{
if (!project_) {
return Write(ErrorMessage(QStringLiteral("render_frame received before load_graph"),
message.ticket_id));
return Write(ErrorMessage(
QStringLiteral("render_frame received before load_graph"),
message.ticket_id));
}
if (!output_pool_ || !output_pool_->IsValid()) {
return Write(ErrorMessage(QStringLiteral("render_frame received before output shm handshake"),
message.ticket_id));
return Write(ErrorMessage(
QStringLiteral(
"render_frame received before output shm handshake"),
message.ticket_id));
}
olive::Node *node = FindNode(message.node_uuid);
if (!node) {
return Write(ErrorMessage(QStringLiteral("render node not found: %1").arg(message.node_uuid),
message.ticket_id));
return Write(
ErrorMessage(QStringLiteral("render node not found: %1")
.arg(message.node_uuid),
message.ticket_id));
}
QVector<int> input_slots;
const QVector<int> requested_input_slots =
message.input_slots.isEmpty() && message.input_slot >= 0
? QVector<int>{message.input_slot}
: message.input_slots;
message.input_slots.isEmpty() && message.input_slot >= 0 ?
QVector<int>{ message.input_slot } :
message.input_slots;
if (!requested_input_slots.isEmpty()) {
if (!input_pool_ || !input_pool_->IsValid()) {
return Write(ErrorMessage(QStringLiteral("render_frame referenced input slot without input pool"),
message.ticket_id));
return Write(ErrorMessage(
QStringLiteral(
"render_frame referenced input slot without input pool"),
message.ticket_id));
}
for (int requested_slot : requested_input_slots) {
@@ -360,8 +392,9 @@ private:
for (int slot : input_slots) {
input_pool_->Release(uint32_t(slot));
}
return Write(ErrorMessage(QStringLiteral("input slot index out of range"),
message.ticket_id));
return Write(ErrorMessage(
QStringLiteral("input slot index out of range"),
message.ticket_id));
}
uint32_t consumed_slot = 0;
@@ -369,16 +402,18 @@ private:
for (int slot : input_slots) {
input_pool_->Release(uint32_t(slot));
}
return Write(ErrorMessage(QStringLiteral("input slot was not ready"),
message.ticket_id));
return Write(
ErrorMessage(QStringLiteral("input slot was not ready"),
message.ticket_id));
}
if (int(consumed_slot) != requested_slot) {
input_pool_->Release(consumed_slot);
for (int slot : input_slots) {
input_pool_->Release(uint32_t(slot));
}
return Write(ErrorMessage(QStringLiteral("input slot order mismatch"),
message.ticket_id));
return Write(ErrorMessage(
QStringLiteral("input slot order mismatch"),
message.ticket_id));
}
input_slots.append(int(consumed_slot));
@@ -389,41 +424,41 @@ private:
}
}
olive::VideoParams vparams(message.width > 0 ? message.width : kDefaultWidth,
message.height > 0 ? message.height : kDefaultHeight,
olive::rational(1, kDefaultFrameRate),
message.format >= 0
? olive::PixelFormat::Format(message.format)
: olive::PixelFormat::F32,
message.channel_count > 0
? message.channel_count
: olive::VideoParams::kRGBAChannelCount);
olive::VideoParams vparams(
message.width > 0 ? message.width : kDefaultWidth,
message.height > 0 ? message.height : kDefaultHeight,
olive::rational(1, kDefaultFrameRate),
message.format >= 0 ? olive::PixelFormat::Format(message.format) :
olive::PixelFormat::F32,
message.channel_count > 0 ? message.channel_count :
olive::VideoParams::kRGBAChannelCount);
olive::RenderTicketPtr ticket = std::make_shared<olive::RenderTicket>();
ticket->setProperty("node", olive::QtUtils::PtrToValue(node));
ticket->setProperty("time", QVariant::fromValue(
olive::rational(int(message.time_num), int(message.time_den))));
ticket->setProperty("time",
QVariant::fromValue(olive::rational(
int(message.time_num), int(message.time_den))));
ticket->setProperty("size", QSize(message.width, message.height));
ticket->setProperty("matrix", QMatrix4x4());
ticket->setProperty("format",
message.format >= 0
? olive::PixelFormat::Format(message.format)
: olive::PixelFormat::INVALID);
message.format >= 0 ?
olive::PixelFormat::Format(message.format) :
olive::PixelFormat::INVALID);
ticket->setProperty("usecache", false);
ticket->setProperty("channelcount", message.channel_count);
ticket->setProperty("mode", olive::RenderMode::Mode(message.mode));
ticket->setProperty("type", olive::RenderManager::kTypeVideo);
ticket->setProperty("colormanager", olive::QtUtils::PtrToValue(project_->color_manager()));
ticket->setProperty("colormanager", olive::QtUtils::PtrToValue(
project_->color_manager()));
{
olive::ColorProcessorPtr color_output;
if (message.has_color_transform) {
QString cache_key =
QStringLiteral("%1|%2|%3|%4")
.arg(message.color_is_display ? 1 : 0)
.arg(message.color_output,
message.color_view,
message.color_look);
QString cache_key = QStringLiteral("%1|%2|%3|%4")
.arg(message.color_is_display ? 1 : 0)
.arg(message.color_output,
message.color_view,
message.color_look);
auto it = color_processor_cache_.find(cache_key);
if (it != color_processor_cache_.end()) {
color_output = it.value();
@@ -431,8 +466,8 @@ private:
olive::ColorTransform transform;
if (message.color_is_display) {
transform = olive::ColorTransform(message.color_output,
message.color_view,
message.color_look);
message.color_view,
message.color_look);
} else {
transform = olive::ColorTransform(message.color_output);
}
@@ -446,19 +481,23 @@ private:
}
}
ticket->setProperty("coloroutput",
QVariant::fromValue(color_output));
QVariant::fromValue(color_output));
}
ticket->setProperty("vparam", QVariant::fromValue(vparams));
ticket->setProperty("aparam", QVariant::fromValue(olive::AudioParams()));
ticket->setProperty("aparam",
QVariant::fromValue(olive::AudioParams()));
ticket->setProperty("return", olive::RenderManager::kFrame);
ticket->setProperty("cache", QString());
ticket->setProperty("cachetimebase", QVariant::fromValue(olive::rational(1)));
ticket->setProperty("cachetimebase",
QVariant::fromValue(olive::rational(1)));
ticket->setProperty("cacheid", QVariant::fromValue(QUuid()));
ticket->setProperty("multicam", olive::QtUtils::PtrToValue(static_cast<void *>(nullptr)));
ticket->setProperty("ipc_input_pool",
olive::QtUtils::PtrToValue(
input_pool_ ? static_cast<void *>(&*input_pool_)
: static_cast<void *>(nullptr)));
ticket->setProperty("multicam", olive::QtUtils::PtrToValue(
static_cast<void *>(nullptr)));
ticket->setProperty(
"ipc_input_pool",
olive::QtUtils::PtrToValue(input_pool_ ?
static_cast<void *>(&*input_pool_) :
static_cast<void *>(nullptr)));
QVariantList input_slot_values;
for (int slot : input_slots) {
input_slot_values.append(slot);
@@ -469,34 +508,42 @@ private:
input_slots.isEmpty() ? -1 : input_slots.front());
ticket->Start();
olive::RenderProcessor::Process(ticket, renderer_, nullptr, &shader_cache_);
olive::RenderProcessor::Process(ticket, renderer_, nullptr,
&shader_cache_);
for (int slot : input_slots) {
input_pool_->Release(uint32_t(slot));
}
if (!ticket->HasResult()) {
return Write(ErrorMessage(QStringLiteral("render produced no frame"), message.ticket_id));
return Write(ErrorMessage(
QStringLiteral("render produced no frame"), message.ticket_id));
}
olive::FramePtr frame = ticket->Get().value<olive::FramePtr>();
if (!frame || !frame->is_allocated()) {
return Write(ErrorMessage(QStringLiteral("render result was empty"), message.ticket_id));
return Write(ErrorMessage(QStringLiteral("render result was empty"),
message.ticket_id));
}
uint32_t slot = 0;
if (!output_pool_->Acquire(&slot)) {
return Write(ErrorMessage(QStringLiteral("no free output frame slot"), message.ticket_id));
return Write(
ErrorMessage(QStringLiteral("no free output frame slot"),
message.ticket_id));
}
const int data_size = frame->linesize_bytes()*frame->height();
const int data_size = frame->linesize_bytes() * frame->height();
if (data_size > int(output_pool_->slot_data_bytes())) {
output_pool_->Release(slot);
LogError(QString("Output frame size")+QString::number(data_size));
LogError(QString("Slot size")+QString::number(output_pool_->slot_data_bytes()));
return Write(ErrorMessage(QStringLiteral("rendered frame does not fit output slot "),
message.ticket_id));
LogError(QString("Output frame size") + QString::number(data_size));
LogError(QString("Slot size") +
QString::number(output_pool_->slot_data_bytes()));
return Write(ErrorMessage(
QStringLiteral("rendered frame does not fit output slot "),
message.ticket_id));
}
std::memcpy(output_pool_->SlotData(slot), frame->const_data(), size_t(data_size));
std::memcpy(output_pool_->SlotData(slot), frame->const_data(),
size_t(data_size));
olive::ipc::FrameSlotMeta *meta = output_pool_->Meta(slot);
meta->id = message.ticket_id;
meta->time_num = frame->timestamp().numerator();
@@ -510,8 +557,9 @@ private:
if (!output_pool_->Publish(slot)) {
output_pool_->Release(slot);
return Write(ErrorMessage(QStringLiteral("failed to publish output frame slot"),
message.ticket_id));
return Write(ErrorMessage(
QStringLiteral("failed to publish output frame slot"),
message.ticket_id));
}
olive::ipc::FrameReadyMsg ready;
ready.ticket_id = message.ticket_id;
@@ -532,7 +580,7 @@ private:
QHash<QString, olive::ColorProcessorPtr> color_processor_cache_;
};
} // namespace
} // namespace
int main(int argc, char *argv[])
{
@@ -600,7 +648,8 @@ int main(int argc, char *argv[])
QOpenGLContext *ctx = nullptr;
if (backend == QStringLiteral("opengl")) {
#ifdef OAK_ENABLE_DYNAMIC_RENDER_BACKEND
if (auto *loaded_renderer = dynamic_cast<olive::DynamicRenderer *>(renderer)) {
if (auto *loaded_renderer =
dynamic_cast<olive::DynamicRenderer *>(renderer)) {
ctx = loaded_renderer->OpenGLContext();
} else
#endif
@@ -639,7 +688,8 @@ int main(int argc, char *argv[])
if (!olive::ipc::ReadMessage(&buffer, &message, &ok)) {
if (!ok) {
olive::ipc::WriteMessage(
&out, ErrorMessage(QStringLiteral("malformed control message")));
&out, ErrorMessage(QStringLiteral(
"malformed control message")));
out.flush();
continue;
}
+1 -1
View File
@@ -22,5 +22,5 @@
void HideWorkerDockIcon()
{
[NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited];
[NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited];
}