From f9e4da4a813600a32a53838eb92d121453477aa9 Mon Sep 17 00:00:00 2001 From: Gary Oberbrunner Date: Wed, 23 Sep 2026 21:08:46 -0400 Subject: [PATCH 1/7] Examples: fix the Test example failing GetClipPreferences on its null inArgs The PropertyTestPlugin checks each action's handles against its own list of which ones may be null, and that list had GetClipPreferences requiring inArgs. The spec passes NULL inArgs to that action, so the plugin answered kOfxStatErrBadHandle and a conforming host could not finish setting up an instance. Every other action's entry matches the spec. Once past that check, the action answered kOfxStatOK having set nothing, which the spec reserves for an action that changed at least one out-arg. It now answers kOfxStatReplyDefault. Found by the new test host. Assisted-by: Claude Code / Claude Opus 5.5 Co-Authored-By: Claude Opus 5.5 Signed-off-by: Gary Oberbrunner --- Examples/Test/testProperties.cpp | 5 +++-- release-notes-next.md | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Examples/Test/testProperties.cpp b/Examples/Test/testProperties.cpp index 24ab3f0b..426d3b20 100644 --- a/Examples/Test/testProperties.cpp +++ b/Examples/Test/testProperties.cpp @@ -966,7 +966,8 @@ getTemporalDomain( OfxImageEffectHandle /*effect*/, OfxPropertySetHandle /*inA static OfxStatus getClipPreferences( OfxImageEffectHandle /*effect*/, OfxPropertySetHandle /*inArgs*/, OfxPropertySetHandle /*outArgs*/) { - return kOfxStatOK; + // we set no preferences, so the host uses its defaults + return kOfxStatReplyDefault; } // are the settings of the effect performing an identity operation @@ -1168,7 +1169,7 @@ pluginMain(const char *action, const void *handle, OfxPropertySetHandle inArgsH checkMainHandles(action, handle, inArgsHandle, outArgsHandle, false, false, false); } else if(OFX::strEquals(action, kOfxImageEffectActionGetClipPreferences)) { - checkMainHandles(action, handle, inArgsHandle, outArgsHandle, false, false, false); + checkMainHandles(action, handle, inArgsHandle, outArgsHandle, false, true, false); stat = getClipPreferences(effectHandle, inArgsHandle, outArgsHandle); } else if(OFX::strEquals(action, kOfxImageEffectActionIsIdentity)) { diff --git a/release-notes-next.md b/release-notes-next.md index 4b8ceac3..99b38a90 100644 --- a/release-notes-next.md +++ b/release-notes-next.md @@ -27,6 +27,7 @@ This is version NEXT of the OpenFX API. - Fixed the ColourSpace example's `OfxSetHost` to have the proper signature so it actually gets called. - Fixed the `@propdef` metadata of `kOfxParamPropChoiceEnum` (a string array, not a bool) and `kOfxParamPropDimensionLabel` (one label per dimension, not one). - Fixed the Invert example never releasing its output image (a shadowed handle variable). +- Fixed the Test example failing `kOfxImageEffectActionGetClipPreferences` with `kOfxStatErrBadHandle` because it required `inArgs`, which the spec passes as NULL for that action; it now answers `kOfxStatReplyDefault`, since it sets no preferences. ## Deprecations From 638cceeda0c926d8afe21fea560752fc861aa41d Mon Sep 17 00:00:00 2001 From: Gary Oberbrunner Date: Wed, 23 Sep 2026 21:09:28 -0400 Subject: [PATCH 2/7] Examples: fix the ChoiceParams example claiming clip preferences it never set Its only clip preference is the output depth, which it sets when the host supports multiple clip depths. On any other host it set nothing and still answered kOfxStatOK, which the spec reserves for an action that changed at least one out-arg. It now answers kOfxStatReplyDefault there, before querying the source clip for a depth it has no use for. Found by the new test host, which warns when a plugin answers kOfxStatOK with nothing written. Assisted-by: Claude Code / Claude Opus 5.5 Co-Authored-By: Claude Opus 5.5 Signed-off-by: Gary Oberbrunner --- Examples/ChoiceParams/choiceparams.cpp | 7 +++++-- release-notes-next.md | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Examples/ChoiceParams/choiceparams.cpp b/Examples/ChoiceParams/choiceparams.cpp index 7019350b..8535d7a7 100644 --- a/Examples/ChoiceParams/choiceparams.cpp +++ b/Examples/ChoiceParams/choiceparams.cpp @@ -195,6 +195,10 @@ getTemporalDomain( OfxImageEffectHandle effect, OfxPropertySetHandle /*inArgs* static OfxStatus getClipPreferences( OfxImageEffectHandle effect, OfxPropertySetHandle /*inArgs*/, OfxPropertySetHandle outArgs) { + // our only preference is the output depth, which needs a host that supports multiple depths + if(!gHostSupportsMultipleBitDepths) + return kOfxStatReplyDefault; + // retrieve any instance data associated with this effect MyInstanceData *myData = getMyInstanceData(effect); @@ -207,8 +211,7 @@ getClipPreferences( OfxImageEffectHandle effect, OfxPropertySetHandle /*inArgs const char *bitDepthStr = bitDepth == 8 ? kOfxBitDepthByte : (bitDepth == 16 ? kOfxBitDepthShort : kOfxBitDepthFloat); // set out output to be the same same as the input bitdepth - if(gHostSupportsMultipleBitDepths) - gPropHost->propSetString(outArgs, "OfxImageClipPropDepth_Output", 0, bitDepthStr); + gPropHost->propSetString(outArgs, "OfxImageClipPropDepth_Output", 0, bitDepthStr); return kOfxStatOK; } diff --git a/release-notes-next.md b/release-notes-next.md index 99b38a90..e38eac56 100644 --- a/release-notes-next.md +++ b/release-notes-next.md @@ -28,6 +28,7 @@ This is version NEXT of the OpenFX API. - Fixed the `@propdef` metadata of `kOfxParamPropChoiceEnum` (a string array, not a bool) and `kOfxParamPropDimensionLabel` (one label per dimension, not one). - Fixed the Invert example never releasing its output image (a shadowed handle variable). - Fixed the Test example failing `kOfxImageEffectActionGetClipPreferences` with `kOfxStatErrBadHandle` because it required `inArgs`, which the spec passes as NULL for that action; it now answers `kOfxStatReplyDefault`, since it sets no preferences. +- Fixed the ChoiceParams example answering `kOfxImageEffectActionGetClipPreferences` with `kOfxStatOK` when it set nothing; it now answers `kOfxStatReplyDefault` unless the host supports multiple clip depths. ## Deprecations From 074655256a84c8d70e90ba5d3d770c94f38b988c Mon Sep 17 00:00:00 2001 From: Gary Oberbrunner Date: Wed, 23 Sep 2026 21:10:39 -0400 Subject: [PATCH 3/7] Examples: fix the ColourSpace example answering OK to actions it ignores Its main entry started from kOfxStatOK and kept it for any action it did not handle, so GetFramesNeeded, Begin/EndSequenceRender, PurgeCaches, SyncPrivateData and the instance edit and change brackets were all answered kOfxStatOK with nothing done. The spec says a plugin returns kOfxStatReplyDefault for an action it does not trap, and for GetFramesNeeded kOfxStatOK means it set a frame range. The entry now starts from kOfxStatReplyDefault, as the comment after its dispatch already said it should, and every action it handles still sets its own status. Found by the new test host, which warns when a plugin answers kOfxStatOK with nothing written. Assisted-by: Claude Code / Claude Opus 5.5 Co-Authored-By: Claude Opus 5.5 Signed-off-by: Gary Oberbrunner --- Examples/ColourSpace/colourspace.cpp | 2 +- release-notes-next.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Examples/ColourSpace/colourspace.cpp b/Examples/ColourSpace/colourspace.cpp index 327a747d..d11257a4 100644 --- a/Examples/ColourSpace/colourspace.cpp +++ b/Examples/ColourSpace/colourspace.cpp @@ -980,7 +980,7 @@ template static OfxStatus pluginMain(const char *action, const void *handle, OfxPropertySetHandle inArgs, OfxPropertySetHandle outArgs) { - OfxStatus stat = kOfxStatOK; + OfxStatus stat = kOfxStatReplyDefault; if (silentActions.find(action) == silentActions.end()) spdlog::info(OFX_FMT_STRING(">>> pluginMain({})"), action); diff --git a/release-notes-next.md b/release-notes-next.md index e38eac56..6161d74f 100644 --- a/release-notes-next.md +++ b/release-notes-next.md @@ -29,6 +29,7 @@ This is version NEXT of the OpenFX API. - Fixed the Invert example never releasing its output image (a shadowed handle variable). - Fixed the Test example failing `kOfxImageEffectActionGetClipPreferences` with `kOfxStatErrBadHandle` because it required `inArgs`, which the spec passes as NULL for that action; it now answers `kOfxStatReplyDefault`, since it sets no preferences. - Fixed the ChoiceParams example answering `kOfxImageEffectActionGetClipPreferences` with `kOfxStatOK` when it set nothing; it now answers `kOfxStatReplyDefault` unless the host supports multiple clip depths. +- Fixed the ColourSpace example answering `kOfxStatOK` to the actions it does not handle, such as `kOfxImageEffectActionGetFramesNeeded`; it now answers `kOfxStatReplyDefault`, as the spec requires of an action a plugin does not trap. ## Deprecations From ced83a3951eeb09ac402d7d74a34ea3e68256f2f Mon Sep 17 00:00:00 2001 From: Gary Oberbrunner Date: Wed, 23 Sep 2026 21:12:43 -0400 Subject: [PATCH 4/7] Examples: fix the ColourSpace example's choice parameters having no enum values describeInContext offers only the colourspaces available in the colour management style it expects the host to use, and the "[Unspecified]" and "[Same as input]" entries were marked Basic. On a host with no colour management every entry was skipped, so the three string-choice parameters had no enum values and no default, which the spec does not allow: the default must be one of the enums. The two entries are now offered in every style, so each parameter has at least that one choice. The "[Unspecified]" entry's enum value was also NULL, passed to propSetString as both an enum and the default whenever the host did have colour management. A host that copies the value into a std::string, as HostSupport does, cannot take that. It is now the empty string, which getClipPreferences already reads as "no preference". Found by the new test host. Assisted-by: Claude Code / Claude Opus 5.5 Co-Authored-By: Claude Opus 5.5 Signed-off-by: Gary Oberbrunner --- Examples/ColourSpace/colourspace.cpp | 6 ++++-- release-notes-next.md | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Examples/ColourSpace/colourspace.cpp b/Examples/ColourSpace/colourspace.cpp index d11257a4..bcbc56f1 100644 --- a/Examples/ColourSpace/colourspace.cpp +++ b/Examples/ColourSpace/colourspace.cpp @@ -61,7 +61,8 @@ ColourManagementStyle ofxstring_to_style(const std::string & style) static space_info input_space_choices[] { - { "[Unspecified, accepts anything]", NULL, ColourManagementStyle::Basic }, + // offered in every style, so the parameter always has a choice + { "[Unspecified, accepts anything]", "", ColourManagementStyle::None }, // For this example plugin we'll offer every possible space defined in the header file // Real plugins do not need this flexibility! @@ -137,7 +138,8 @@ static space_info input_space_choices[] static space_info output_space_choices[] { - { "[Same as input]", "OfxColourspace_Source", ColourManagementStyle::Basic }, + // offered in every style, so the parameter always has a choice + { "[Same as input]", "OfxColourspace_Source", ColourManagementStyle::None }, // For this example plugin we'll offer every possible space defined in the header file // Real plugins do not need this flexibility! diff --git a/release-notes-next.md b/release-notes-next.md index 6161d74f..1adf14d6 100644 --- a/release-notes-next.md +++ b/release-notes-next.md @@ -30,6 +30,7 @@ This is version NEXT of the OpenFX API. - Fixed the Test example failing `kOfxImageEffectActionGetClipPreferences` with `kOfxStatErrBadHandle` because it required `inArgs`, which the spec passes as NULL for that action; it now answers `kOfxStatReplyDefault`, since it sets no preferences. - Fixed the ChoiceParams example answering `kOfxImageEffectActionGetClipPreferences` with `kOfxStatOK` when it set nothing; it now answers `kOfxStatReplyDefault` unless the host supports multiple clip depths. - Fixed the ColourSpace example answering `kOfxStatOK` to the actions it does not handle, such as `kOfxImageEffectActionGetFramesNeeded`; it now answers `kOfxStatReplyDefault`, as the spec requires of an action a plugin does not trap. +- Fixed the ColourSpace example declaring its string-choice parameters with no enum values on a host without colour management, and passing a NULL string as the "unspecified" input colourspace on one with it. ## Deprecations From 790ae7bf462b7c776088f1a3c217f08426a1bdba Mon Sep 17 00:00:00 2001 From: Gary Oberbrunner Date: Wed, 23 Sep 2026 21:15:45 -0400 Subject: [PATCH 5/7] Examples: fix the ColourSpace example's text overrunning small frames drawText clipped the text it draws at the top and right of the image but not at the bottom or left. Render places its three lines of text 100 pixels in from the left and top edges, each line 50 pixels below the last at full scale, so on a frame under 200 pixels high a line starts below row 0 and drawText wrote it before the start of the image data. It now starts each loop at the image's edge. Found by the new test host, which puts guard bytes around every image. Assisted-by: Claude Code / Claude Opus 5.5 Co-Authored-By: Claude Opus 5.5 Signed-off-by: Gary Oberbrunner --- Examples/ColourSpace/colourspace.cpp | 15 ++++++++------- release-notes-next.md | 1 + 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Examples/ColourSpace/colourspace.cpp b/Examples/ColourSpace/colourspace.cpp index bcbc56f1..648f5d84 100644 --- a/Examples/ColourSpace/colourspace.cpp +++ b/Examples/ColourSpace/colourspace.cpp @@ -273,7 +273,8 @@ static constexpr T lerp(T a, T b, float amount) { } while (0) /** - * Draw a string of text at the given position in the image + * Draw a string of text at the given position in the image, clipped to + * its xdim x ydim pixels */ static void drawText(const std::string &message, int x, int y, unsigned int font_height, @@ -294,10 +295,10 @@ static void drawText(const std::string &message, int x, int y, float white = 255.0f; float color_scale = 1.0f/256.0f; float bg_opacity = 0.2f; - for (int iy = y, ty = 0; iy < ydim && ty < txt_height; iy++, ty++) { + for (int iy = std::max(y, 0), ty = iy - y; iy < ydim && ty < txt_height; iy++, ty++) { T *row = (T *)((unsigned char *)image + iy * rowbytes); float *txt_row = txt_img.data(0, txt_height - 1 - ty); - for (int ix = x, tx = 0; ix < xdim && tx < txt_width; ix++, tx++) { + for (int ix = std::max(x, 0), tx = ix - x; ix < xdim && tx < txt_width; ix++, tx++) { switch (nchannels) { case 1: // Alpha only row[ix*4] = std::max(row[ix*4], (T)(txt_row[tx] * color_scale)); @@ -320,10 +321,10 @@ static void drawText(const std::string &message, int x, int y, float white = 65535.0f; float color_scale = 1.0f/65536.0f; float bg_opacity = 0.2f; - for (int iy = y, ty = 0; iy < ydim && ty < txt_height; iy++, ty++) { + for (int iy = std::max(y, 0), ty = iy - y; iy < ydim && ty < txt_height; iy++, ty++) { T *row = (T *)((unsigned char *)image + iy * rowbytes); float *txt_row = txt_img.data(0, txt_height - 1 - ty); - for (int ix = x, tx = 0; ix < xdim && tx < txt_width; ix++, tx++) { + for (int ix = std::max(x, 0), tx = ix - x; ix < xdim && tx < txt_width; ix++, tx++) { switch (nchannels) { case 1: // Alpha only row[ix*4] = std::max(row[ix*4], (T)(txt_row[tx] * color_scale)); @@ -344,10 +345,10 @@ static void drawText(const std::string &message, int x, int y, case 32: { float white = 1.0f; float bg_opacity = 0.2f; - for (int iy = y, ty = 0; iy < ydim && ty < txt_height; iy++, ty++) { + for (int iy = std::max(y, 0), ty = iy - y; iy < ydim && ty < txt_height; iy++, ty++) { float *row = (float *)((unsigned char *)image + iy * rowbytes); float *txt_row = txt_img.data(0, txt_height - 1 - ty); - for (int ix = x, tx = 0; ix < xdim && tx < txt_width; ix++, tx++) { + for (int ix = std::max(x, 0), tx = ix - x; ix < xdim && tx < txt_width; ix++, tx++) { switch (nchannels) { case 1: // Alpha only row[ix*4] = std::max(row[ix*4], txt_row[tx]); diff --git a/release-notes-next.md b/release-notes-next.md index 1adf14d6..f08ec82b 100644 --- a/release-notes-next.md +++ b/release-notes-next.md @@ -31,6 +31,7 @@ This is version NEXT of the OpenFX API. - Fixed the ChoiceParams example answering `kOfxImageEffectActionGetClipPreferences` with `kOfxStatOK` when it set nothing; it now answers `kOfxStatReplyDefault` unless the host supports multiple clip depths. - Fixed the ColourSpace example answering `kOfxStatOK` to the actions it does not handle, such as `kOfxImageEffectActionGetFramesNeeded`; it now answers `kOfxStatReplyDefault`, as the spec requires of an action a plugin does not trap. - Fixed the ColourSpace example declaring its string-choice parameters with no enum values on a host without colour management, and passing a NULL string as the "unspecified" input colourspace on one with it. +- Fixed the ColourSpace example writing its text overlay past the bottom and left edges of a frame too small to hold it. ## Deprecations From 54c74baa8510bad14a96c73d027ceb2a694fc9c4 Mon Sep 17 00:00:00 2001 From: Gary Oberbrunner Date: Wed, 23 Sep 2026 21:20:49 -0400 Subject: [PATCH 6/7] Examples: fix the ColourSpace example's rendering of tiles Render copied the source to the output with one memcpy of the source's row bytes times its height, starting at the output's data pointer, as if the output were the whole frame. It declares tile support, and a tile's output image covers only the render window, so each tile got a copy of the frame's bottom left corner and the copy ran on past the end of the output buffer. When the source image was allocated just after it, the two ranges overlapped: the intermittent crash that ASan reports as memcpy-param-overlap. It now copies the render window a row at a time, addressing each image through its own bounds and row bytes, so it no longer needs the two row bytes to match, and it fills with black whatever part of the window the source does not cover. Tiled and whole-frame renders also differed for a second reason: the text was placed relative to the output image, so every tile drew its own copy in its own corner. The text is now placed relative to the output's region of definition, which also gives the frame size it reports in place of the source image's bounds, and drawn into the render window, which drawText clips it to on all four sides since the previous commit, so a tiled render is identical to a whole one. A whole-frame render is unchanged. Found by the new test host, with --tiles and --check-tiles. Assisted-by: Claude Code / Claude Opus 5.5 Co-Authored-By: Claude Opus 5.5 Signed-off-by: Gary Oberbrunner --- Examples/ColourSpace/colourspace.cpp | 54 ++++++++++++++++++++-------- release-notes-next.md | 1 + 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/Examples/ColourSpace/colourspace.cpp b/Examples/ColourSpace/colourspace.cpp index 648f5d84..141c3ee4 100644 --- a/Examples/ColourSpace/colourspace.cpp +++ b/Examples/ColourSpace/colourspace.cpp @@ -688,6 +688,12 @@ static std::string getClipColourspace(const OfxImageClipHandle clip) { } +// the address of pixel (x, y) in an image whose data starts at its bounds' bottom left +static char *pixelAddress(void *data, const OfxRectI &bounds, int rowBytes, int bytesPerPixel, int x, int y) +{ + return (char *)data + (y - bounds.y1) * rowBytes + (x - bounds.x1) * bytesPerPixel; +} + static OfxStatus render( OfxImageEffectHandle instance, OfxPropertySetHandle inArgs, OfxPropertySetHandle /*outArgs*/) @@ -746,33 +752,51 @@ static OfxStatus render( OfxImageEffectHandle instance, outputImg = ofxuGetImage(myData->outputClip, time, dstRowBytes, dstBitDepth, dstIsAlpha, dstRect, dst); if(outputImg == NULL) throw OfxuNoImageException(); - // see if they have the same depths and bytes and all - if(srcBitDepth != dstBitDepth || srcIsAlpha != dstIsAlpha || srcRowBytes != dstRowBytes) { + // see if they have the same depths and all + if(srcBitDepth != dstBitDepth || srcIsAlpha != dstIsAlpha) { throw OfxuStatusException(kOfxStatErrImageFormat); } - int xdim = srcRect.x2 - srcRect.x1; - int ydim = srcRect.y2 - srcRect.y1; + // the whole frame, of which the render window may be one tile + OfxRectI frame; + gPropHost->propGetIntN(outputImg, kOfxImagePropRegionOfDefinition, 4, &frame.x1); + int xdim = frame.x2 - frame.x1; + int ydim = frame.y2 - frame.y1; // do the rendering int nchannels = 4; + int bytesPerPixel = nchannels * dstBitDepth / 8; int font_height = 50 * renderScale[0]; - spdlog::info(OFX_FMT_STRING("Rendering {}x{} image @{},{}, depth={}"), xdim, ydim, srcRect.x1, srcRect.y1, dstBitDepth); - - // Just copy from source to dest, and draw some text - if (srcRowBytes < 0 && dstRowBytes < 0) - memcpy((char *)dst + dstRowBytes * (ydim-1), (char*)src + srcRowBytes * (ydim-1), -srcRowBytes * ydim); - else - memcpy(dst, src, srcRowBytes * ydim); - int ystart = ydim - 100; + spdlog::info(OFX_FMT_STRING("Rendering {}x{} image @{},{}, depth={}"), xdim, ydim, frame.x1, frame.y1, dstBitDepth); + + int windowWidth = renderWindow.x2 - renderWindow.x1; + int windowHeight = renderWindow.y2 - renderWindow.y1; + + // Copy the render window from source to dest a row at a time, as each + // image has its own bounds and row bytes; black where there is no source + for (int y = renderWindow.y1; y < renderWindow.y2; y++) { + char *dstRow = pixelAddress(dst, dstRect, dstRowBytes, bytesPerPixel, renderWindow.x1, y); + memset(dstRow, 0, windowWidth * bytesPerPixel); + int x1 = std::max(renderWindow.x1, srcRect.x1); + int x2 = std::min(renderWindow.x2, srcRect.x2); + if (y >= srcRect.y1 && y < srcRect.y2 && x1 < x2) + memcpy(dstRow + (x1 - renderWindow.x1) * bytesPerPixel, + pixelAddress(src, srcRect, srcRowBytes, bytesPerPixel, x1, y), + (x2 - x1) * bytesPerPixel); + } + + // Draw some text, placed in the frame and clipped to the render window + char *window = pixelAddress(dst, dstRect, dstRowBytes, bytesPerPixel, renderWindow.x1, renderWindow.y1); + int xstart = frame.x1 + 100 - renderWindow.x1; + int ystart = frame.y2 - 100 - renderWindow.y1; drawText(fmt::format(OFX_FMT_STRING("Image: {}x{}, depth={}, scale={:.2f}x{:.2f}"), xdim, ydim, dstBitDepth, renderScale[0], renderScale[1]), - 100, ystart, font_height, dst, xdim, ydim, dstBitDepth, nchannels, dstRowBytes); + xstart, ystart, font_height, window, windowWidth, windowHeight, dstBitDepth, nchannels, dstRowBytes); ystart -= font_height; drawText(fmt::format(OFX_FMT_STRING("input colourspace: {}"), inputColourspace), - 100, ystart, font_height, dst, xdim, ydim, dstBitDepth, nchannels, dstRowBytes); + xstart, ystart, font_height, window, windowWidth, windowHeight, dstBitDepth, nchannels, dstRowBytes); ystart -= font_height; drawText(fmt::format(OFX_FMT_STRING("output colourspace: {}"), outputColourspace), - 100, ystart, font_height, dst, xdim, ydim, dstBitDepth, nchannels, dstRowBytes); + xstart, ystart, font_height, window, windowWidth, windowHeight, dstBitDepth, nchannels, dstRowBytes); } catch(OfxuNoImageException &ex) { // if we were interrupted, the failed fetch is fine, just return kOfxStatOK diff --git a/release-notes-next.md b/release-notes-next.md index f08ec82b..ccc1b93c 100644 --- a/release-notes-next.md +++ b/release-notes-next.md @@ -32,6 +32,7 @@ This is version NEXT of the OpenFX API. - Fixed the ColourSpace example answering `kOfxStatOK` to the actions it does not handle, such as `kOfxImageEffectActionGetFramesNeeded`; it now answers `kOfxStatReplyDefault`, as the spec requires of an action a plugin does not trap. - Fixed the ColourSpace example declaring its string-choice parameters with no enum values on a host without colour management, and passing a NULL string as the "unspecified" input colourspace on one with it. - Fixed the ColourSpace example writing its text overlay past the bottom and left edges of a frame too small to hold it. +- Fixed the ColourSpace example under tiled rendering: it copied the whole source image to the start of each tile, overrunning the output buffer, and drew its text relative to each tile. It now copies only the render window and places the text in the frame. ## Deprecations From be1dce87e6214696744a04887ceb55e1f4b742ad Mon Sep 17 00:00:00 2001 From: Gary Oberbrunner Date: Wed, 23 Sep 2026 22:52:06 -0400 Subject: [PATCH 7/7] Examples: fix the DepthConverter example's clip preferences It set the output clip's depth from its parameter whatever the host said, though a plugin may change a clip's depth only on a host that supports multiple clip depths, and it answered kOfxStatOK even when its parameter mapped to no depth and it had set nothing. It now keeps the host's preferences in both cases, with kOfxStatReplyDefault. It also no longer reads the host's support for multiple clip depths into an uninitialised local, keeping it for the action instead. Assisted-by: Claude Code / Claude Opus 5.5 Co-Authored-By: Claude Opus 5.5 Signed-off-by: Gary Oberbrunner --- Examples/DepthConverter/depthConverter.cpp | 12 +++++++++--- release-notes-next.md | 1 + 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Examples/DepthConverter/depthConverter.cpp b/Examples/DepthConverter/depthConverter.cpp index 241c3782..223df31e 100644 --- a/Examples/DepthConverter/depthConverter.cpp +++ b/Examples/DepthConverter/depthConverter.cpp @@ -31,6 +31,7 @@ static bool gSupportsBytes = false; static bool gSupportsShorts = false; static bool gSupportsFloats = false; static int gDepthParamToBytes[3]; // maps the value of the bit depth param to a host supported bit depth +static int gHostSupportsMultipleDepths = 0; // whether the host lets the output depth differ from the input's // pointers64 to various bits of the host OfxHost *gHost; @@ -374,6 +375,10 @@ getClipPreferences(OfxImageEffectHandle effect, OfxPropertySetHandle /*inArgs*/, OfxPropertySetHandle outArgs) { + // only a host that supports multiple clip depths lets us change the output's + if(!gHostSupportsMultipleDepths) + return kOfxStatReplyDefault; + // retrieve any instance data associated with this effect MyInstanceData *myData = getMyInstanceData(effect); @@ -389,6 +394,8 @@ getClipPreferences(OfxImageEffectHandle effect, case 16 : gPropHost->propSetString(outArgs, "OfxImageClipPropDepth_Output", 0, kOfxBitDepthShort); break; // float case 32 : gPropHost->propSetString(outArgs, "OfxImageClipPropDepth_Output", 0, kOfxBitDepthFloat); break; + // no depth the host supports, so nothing to set + default : return kOfxStatReplyDefault; } return kOfxStatOK; @@ -461,9 +468,8 @@ describe(OfxImageEffectHandle effect) if((stat = ofxuFetchHostSuites()) != kOfxStatOK) return stat; - int hostSupportsMultipleDepths; // record a few host features - gPropHost->propGetInt(gHost->host, kOfxImageEffectPropSupportsMultipleClipDepths, 0, &hostSupportsMultipleDepths); + gPropHost->propGetInt(gHost->host, kOfxImageEffectPropSupportsMultipleClipDepths, 0, &gHostSupportsMultipleDepths); // see how many bit depths the host supports, this affects our parameter values int nHostDepths; @@ -471,7 +477,7 @@ describe(OfxImageEffectHandle effect) // If the host cannot support multiple bit depths on in and out clips or it only supports 1 bit depth // we can't do any work, so refuse to load and explain why. - if(!hostSupportsMultipleDepths || nHostDepths == 1) { + if(!gHostSupportsMultipleDepths || nHostDepths == 1) { // post a message // - disabled, because posting a message within describe() crashes Nuke 6 //gMessageSuite->message(effect, kOfxMessageError, kMessageNotEnoughBits, diff --git a/release-notes-next.md b/release-notes-next.md index ccc1b93c..e5ce9fe3 100644 --- a/release-notes-next.md +++ b/release-notes-next.md @@ -33,6 +33,7 @@ This is version NEXT of the OpenFX API. - Fixed the ColourSpace example declaring its string-choice parameters with no enum values on a host without colour management, and passing a NULL string as the "unspecified" input colourspace on one with it. - Fixed the ColourSpace example writing its text overlay past the bottom and left edges of a frame too small to hold it. - Fixed the ColourSpace example under tiled rendering: it copied the whole source image to the start of each tile, overrunning the output buffer, and drew its text relative to each tile. It now copies only the render window and places the text in the frame. +- Fixed the DepthConverter example asking for an output depth different from its input's on a host that does not support multiple clip depths, and claiming clip preferences it had not set. ## Deprecations