Migration guide for rendering between Prysm versions

Transitioning to Prysm 1.2

This section outlines the changes you need to apply in order to upgrade from Prysm versions 1.1 and prior to 1.2 and later.

The current backend API was designed around DirectX 11 and therefore implementing a DirectX 11 backend with the current API is simple and intuitive. However, with the advent of modern low-level APIs (e.g. Dx12, Metal and Vulkan) and concepts such as render passes, enhancements of the backend API where needed, so that the backend implementation for those graphics APIs is easier and more efficient.

You can read more about the motivation for the backend API changes here.

In Prysm 1.2, Renoir's backend API has been modified significantly with the introduction of 2 new commands, 4 new Renoir Core capabilities and one new shader type. There are also several changes in the graphics backend that must be adapted from previous versions for the new version to work.

If you prefer to make minimal changes to your backend and not use the new capabilities, here are the steps for migrating:

  • Add the following lines to the FillCaps method
    outCaps.ShouldUseRenderPasses = false;
    outCaps.ShouldClearRTWithClearQuad = false;
    outCaps.ConstantBufferBlocksCount = 1;
    outCaps.ConstantBufferRingSize = 1;
    outCaps.ShaderMapping[ST_ClearQuad] = ST_ClearQuad;
  • Add unsigned size as last argument of the CreateConstantBuffer method and use it for the constant buffer allocation size. This is how the CreateConstantBuffer method declaration in the backend header should look like:
    virtual bool CreateConstantBuffer(CBType type, ConstantBufferObject object, unsigned size) override;
    Example of using the size parameter on constant buffer creation from the DirectX11 backend:
    bool Dx11Backend::CreateConstantBuffer(CBType, ConstantBufferObject object, unsigned size)
    D3D11_BUFFER_DESC bufferDesc;
    bufferDesc.ByteWidth = size;
    // Create the constant buffer with the filled buffer description
    m_Device->CreateBuffer(&bufferDesc, ..)
  • In SetRenderTarget stop using EnableColorWrites flag, as it is no longer present and instead handle the PipelineState's ColorMask field in CreatePipelineState. This field currently only supports the values ColorWriteMask:CWM_None and ColorWriteMask::CWM_All, which correspond to the previous false and true values of EnableColorWrites. Set the appropriate value of the graphics API's render target color write mask. E.g. in DirectX11 the write mask is placed in the description of the blend state:
    bool Dx11Backend::CreatePipelineState(const PipelineState& state, PipelineStateObject object)
    D3D11_BLEND_DESC desc;
    desc.RenderTarget[0].RenderTargetWriteMask = UINT8(state.ColorMask);
    // Create the blend state with the filled description
    m_Device->CreateBlendState(&desc, ...)
  • In ExecuteRendering add empty cases with only a break statement in them for BC_BeginRenderPass and BC_EndRenderPass:
    case BC_BeginRenderPass:
    case BC_EndRenderPass:

The MSAASamples field was added to the PipelineState structure, so you may start using it in CreatePipelineState.

Below we will describe each new capability, how it can affect your backend, and what the needed changes you need to make to use it are.

When the ShouldUseRenderPasses capability is enabled, Renoir will start enqueuing the commands BeginRenderPass and EndRenderPass and stop issuing the SetRenderTarget and ResolveRenderTarget commands. The BeginRenderPass command provides all the needed information for starting a render pass in modern graphics APIs like Metal and Vulkan. This information includes the render targets, whether they should be cleared on a render pass load, and if they should be resolved on store. Here are the additional steps you need to make to start using this capability:

  • Set ShouldUseRenderPasses to true in the FillCaps method
  • You can remove the implementation of the SetRenderTarget and ResolveRenderTarget methods and add an assert that they are never called
  • Implement a BeginRenderPass method, which will handle the corresponding command by using the provided information by it to begin a render pass in the graphics API
  • Implement an EndRenderPass method, which will handle the corresponding command by ending the current render pass, and possibly also reset any currently kept state of the render pass. E.g. in our Metal backend, the implementation of the EndRenderPass method is the following:
    [m_State->CurrentCmdEncoder endEncoding];
    m_State->CurrentCmdEncoder = nil;
    m_State->BoundGPUState = GPUState();

Enabling the ShouldClearRTWithClearQuad capability will make Renoir issue a fullscreen clear quad, instead of calling ClearRenderTarget. The clear quad is done through a new vertex and pixel shader. The capability was added so that we don't need to create a new render pass to clear a render target in graphics APIs like Metal, which does not provide an easier way to do it. Here are the additional steps you need to make to start using this capability:

  • Set ShouldClearRTWithClearQuad to true in the FillCaps method
  • You can remove the implementation of the ClearRenderTarget method and add an assert that it is never called
  • You need to create a new ST_ClearQuad vertex and pixel shader, compile them if necessary and start using them. You can check out the example ST_ClearQuad HLSL shaders provided with the DirectX11 backend. The Metal backend is using the clear quad capability, so you can check out how to use the new shaders in its implementation.

The ConstantBufferRingSize capability allows you to set the size of the internal ring buffer, which is used to manage Renoir's constant buffers. We recommend setting this size to 4 for low-level graphics APIs like Dx12, Metal and Vulkan. The motivation for this particular size is that the maximum count of buffered frames in a standard pipeline is 3, and in order to surely avoid an overlap of constant buffers, they should be managed by a circular buffer with size 4. If you have a pipeline with a higher maximum count of buffered frames, then this value should be changed accordingly. For most high-level graphics APIs, the ring buffer size should be set to 1, because the drivers for them handle constant buffer overlap internally, and therefore a greater value for the ring buffer size is unnecessary.

The only steps you need to make to start using this capability are:

  • Set ConstantBufferRingSize to the appropriate value in the FillCaps method
  • If you have a ring buffer for the constant buffers in your backend, then you can remove it, because Renoir will do it automatically for you

The ConstantBufferBlocksCount capability allows you to set the count of aligned constant buffer blocks for each constant buffer type. Renoir will issue a CreateConstantBuffer call with a size equal to (constant buffer blocks count) * (aligned specific constant buffer size) for each constant buffer type. If the blocks count value is greater than 1, then if the regular constant buffer becomes full, Renoir will make sure that a new auxiliary constant buffer is allocated. If the blocks count value is equal to 1, then Renoir won't create any auxiliary constant buffers. Auxiliary constant buffers are allocated per frame, thus being allocated before ExecuteRendering is called and deallocated immediately after that. Setting constant buffer ring size and blocks count value to greater than 1 usually goes hand in hand, because both provide functionality that otherwise should be explicitly implemented in the backend for low-level graphics APIs like Dx12, Metal and Vulkan. For other APIs that don't support constant buffers, but use uniform slots (e.g OpenGL) both capabilities should be set to 1 to avoid unnecessary constant buffer creation.

The only steps you need to make, so you can start using this capability are:

  • Set ConstantBufferBlocksCount to the appropriate value in the FillCaps method
  • Remove all the logic in your backend, which manually creates auxiliary buffers once the regular ones are full. Renoir will create and manage them automatically

Transitioning to Prysm 1.8

Prysm version 1.8 introduces support for using images that do not have their alpha channel premultiplied into the other color channels. Prior to version 1.8, all images in the SDK were treated as if they were using premultiplied alpha, disregarding any image metadata that might tell otherwise.

User images (images that are preloaded by the engine, instead of decoded internally by Prysm) can now specify whether their alpha channel is premultiplied via the new cohtml::IAsyncResourceResponse::UserImageData::AlphaPremultiplication property. You can set the property to the correct value in the UserImageData object that is passed to the cohtml::IAsyncResourceResponse::ReceiveUserImage API in the cohtml::IAsyncResourceHandler::OnResourceRequest callback of your resource handler. This allows you to re-use the same image in both your engine and UI, even if the engine uses a non-premultiplied alpha pipeline.

Following is a table that describes the differences and solutions for various image formats:

Format 1.7 and prior 1.8
PNG, JPG, Other RGB(A) formats Automatically premultiplied after decode No change - Automatically premultiplied after decode
DDS Assumed to have premultiplied alpha May need to re-save - Attempts to determine if alpha is premultiplied from metadata
KTX, ASTC, PKM Assumed to have premultiplied alpha Must re-save - Assumed NOT to have premultiplied alpha
User images Assumed to have premultiplied alpha User controlled via cohtml::IAsyncResourceResponse::UserImageData::AlphaPremultiplication

Note that the output of all operations in the Prysm is still an alpha-premultiplied texture, so the blending of the resulting UI texture is not affected.

Transitioning to Prysm 1.9

Prysm version 1.9 introduces two new features in all example backends - user texture and user depth stencil lifetime event callbacks and custom allocators.

User resources callbacks

User texture and depth stencil callbacks give the user the ability to be informed about user texture wrapping, destruction, user depth stencil wrapping and destruction. To enable this functionality, the user is required to provide a class that inherits from IUserResourcesListener by calling the SetUserResourcesListener of the used backend. The backend will then inform the user about relevant events as they happen. If no such IUserResourcesListener is set, all backends will continue to work as they currently do. It's proper to point out that destruction callbacks will only be called for resources that have been wrapped after providing an IUserResourcesListener.


// Create an instance of a class that inherits IUserResourcesListener
EngineResourceListener m_EngineResourceListener(...);
// Create a backend and initialize it
auto dx11 = new renoir::Dx11Backend(...);
if (!dx11->InitializeStaticResources())
APP_LOG(Error, "Unable to initialize backend static resources!");
return false;
// Set the texture listener
// Wrap a user resource - texture/depth stencil
dx11->WrapUserTexture(userObject, description, object);
// Destroy a user resource - texture/depth stencil
// Receive a callback in the EngineResourceListener::OnUserTextureDestroyed() callback
void EngineResourceListener::OnUserTextureDestroyed(void* userObject)
// Inform the engine that the texture is no longer being used

Custom backend allocators

The second and bigger feature is the addition of user backend allocators that are used to allocate memory for data in the backends. Please note, that this memory is only used by the backend itself, but it does not encompass memory needed by graphics driver calls (e.g. D3D). While for some backends this memory is required from the user anyway (e.g. PS4), in general, the feature doesn't target those kinds of allocations. To provide an allocator to the backend, the user might supply an object that implements the IBackendAllocator interface to the backend constructor. Once set, the allocator should NOT be changed and should be used for the whole lifetime of the backend. If no such allocator is set, everything will continue to work as it has until now, as there's a default malloc/free-based allocator provided.

Due to the specifics of each backend, there are some differences in the way (and cases where) these allocators are used.

  • For all backends, the allocator is used for dynamically allocated objects and all STL-based containers and STL-based objects.
  • For the NVN backend - the allocator is also used for GPU allocations under the hood.
  • For the Vulkan backend - if no VulkanBackendAllocator is provided in its constructor, the default VulkanBackendAllocator implementation uses the IBackendAllocator passed to the VulkanBackend (if one is given) for allocations made inside it.
  • For the PS4 backend - the memory allocators that were passed in the constructor had their types changed to IBackendAllocator and are now used for everything that they were previously used for with the following improvement - the Onion allocator now additionally handles the dynamic allocations inside the backend. Requires user changes.
  • For the PS5 backend - the memory allocator that was passed in the constructor had its type changed to IBackendAllocator and is now used for everything that it was used so far, plus all dynamic allocations inside the backend. Requires user changes.


// Create an instance of a class that inherits IBackendAllocator
EngineBackendAllocator m_EngineBackendAllocator(...);
// Create a backend and initialize it with the desired custom IBackendAllocator
auto dx11 = new renoir::Dx11Backend(
m_Renderer.get())->GetDevice(), false, m_PreferCPUWorkload, &m_EngineBackendAllocator);
// All backend allocations will now use the m_EngineBackendAllocator
// Again note that depending on the backend used, graphics driver calls may or may not
// use the custom allocator for allocation.

Transitioning to Prysm 1.9.5

New fields in the renoir::RendererCaps structure.

There are 2 new fields in the renoir::RendererCaps structure: renoir::RendererCaps::MaxTextureWidth and renoir::RendererCaps::MaxTextureHeight. The default versions of all backends are updated to fill in these values, which represent the maximum possible width and height of a 2D texture for the device, respectively. These values are used to limit the size of temporary textures that the Renoir library creates. A good default is 8192 by 8192 pixels, which is what was used internally before exposing these options.

It is required to provide correct values to the renoir::RendererCaps::MaxTextureWidth and renoir::RendererCaps::MaxTextureHeight fields since otherwise these limits will end up with uninitialized values and lead to undefined behavior.

Transition from Prysm 1.10 to 1.11

Changes related to the experimental new SDF generation on GPU

  • As all of the below require user changes, you can see reference implementations in the provided backends.
  • Two new capabilities were added to the RendererCaps structure - CanOutputDepthInPixelShader and SupportsTwoSidedStencilOperations. Both must be supported by a given backend in order for the SDF-on-GPU to work. In the case of at least one of them not being true, the fallback to the old algorithm is used. Need to be set by user backends.
  • New ShaderTypes(ST_GenerateSDFOutline, ST_GenerateSDFSolid, ST_RenderSDF and ST_ClearQuadWithDepth) and shader mappings in the capabilities of the backend corresponding to the mentioned new shader types. Usually, the pattern is as follows, but it's still subject to change. The mapping is done in the void FillCaps(RendererCaps& outCaps) method. Need to be set by user backends. They can be dummy values if the new feature is not used.
    outCaps.ShaderMapping[ST_GenerateSDFOutline] = ST_GenerateSDFOutline;
    outCaps.ShaderMapping[ST_GenerateSDFSolid] = ST_StandardRare;
    outCaps.ShaderMapping[ST_RenderSDF] = ST_Standard;
    outCaps.ShaderMapping[ST_ClearQuadWithDepth] = ST_ClearQuadWithDepth;
  • New PixelShaderTypes must be implemented in user shaders, in order for the feature to work. These values are also subject to change. Need to be implemented by the user shaders for the feature to work. May be skipped otherwise.
    PST_SDFGenerateOutline = 20, // Generates the outline part of the glyph
    PST_SDFGenerateSolid = 21, // Generates the solid part of the glyph
    PST_SDFRender = 22, // Renders glyphs when drawing text
    PST_SDFOutlineRender = 23, // Renders glyphs with outline when drawing text
  • Two new shaders - the ClearQuadWithDepth pixel shader and the GenerateSDF pixel shader. Need to be implemented by the user backend in order for the feature to work. May be skipped otherwise.
    • The ClearQuadWithDepth one is only needed in backends that support the ShouldClearRTWithClearQuad capability. It does the work of the ClearQuad pixel shader with the additional depth clearing to a given value. Backends that clear render targets with the ClearQuad shader, but can't implement this one can't use the new feature.
    • The GenerateSDF one is needed in backends that support the canOutputDepthInPixelShader and it generates glyph outlines (the first step in the glyph generation process). Backends that can't implement it for whatever reason can't use the new feature
  • Changed the StencilFunc type to ComparisonFunction type along with its values and all references to them in order for this variable to better reflect its new usage (depth functions, stencil functions and so on). This affects the PipelineState objects. Users might need to check compatibility in their backends.
  • Changed the BeginRenderPassCmd backend command to reflect those changes - added ShouldClearDepth, ClearDepthValue and RTFormat. Users might need to check compatibility in their backends.

Transition to Prysm

Introduction of MSDF user fonts

So far, we only had support for offline user-generated Bitmap fonts. In this version, we are introducing offline user-generated MSDF font support.

  • The ST_RenderSDF shader type was removed and new ST_TextSDFGPU, ST_TextStrokeSDFGPU, ST_BatchedTextSDFGPU, ST_TextMSDF, ST_TextStrokeMSDF and ST_BatchedTextMSDF shader types were introduced and added to the shader mappings. The first three are used for rendering of SDF fonts generated on the GPU, while the other three are used for the newly introduced MSDF rendering. Client attention/changes required!
  • The PST_SDFRender and PST_SDDOutlineRender pixel shader source was moved from the CohShadeGeometry.ihlsl file to the CohShadeGeometryRare.ihlsl one. Client attention/changes required!
  • The PST_MSDFRender and PST_MSDFOutlineRender pixel shader types were implemented in the CohShadeGeometryRare.ihlsl file. Client attention/changes required!

Changes related to the user font API

With the introduction of another type of user font, we decided to simplify the API for loading user fonts.

  • As a result, we are no longer using the old cohtml::System::BitmapFontDescription object, but the new cohtml::System::UserFontDescription one. Aside from the changed name, it has two new parameters. The first is the type of the font, which specifies whether we are using the old Bitmap font logic, or the newly introduced MSDF one. The second one is the spread, which should be set to 0 in the case of Bitmap fonts and to the correct value for fonts that are using distance fields like the MSDF fonts, for example.
  • The pair of cohtml::System::AddBitmapFont functions have been changed to a pair of cohtml::System::AddUserFont ones, that take the new cohtml::System::UserFontDescription configuration object instead of the old cohtml::System::BitmapFontDescription one. This means that all references to that type (and its subtypes) should be changed to reflect how the new API works.

Transition to Prysm 1.13

Changes related shader mapping in the backends

  • Until 1.13 when we wanted to clear the depth in the current RT when the capability for clearing with a fullscreen triangle was enabled, we used the ST_ClearQuadWithDepth shader type which was writing depth in the pixel shader. Now we'll use the geometry to set Z values in the depth buffer and we'll use the ST_ClearQuad shader type.

Changes related to font rendering

  • Text can be drawn on fractional pixel coordinates. Until now, the position of a text run has always been snapped to the nearest whole pixel. This can lead to bad-looking text animations. Because of that, we've decided that we want to lift this restriction and allow texts to be positioned on fractional coordinates. This is a change that breaks backward compatibility and there is no way to enable the position snapping again. The images below show the difference between before and after this change for text positioned at a 0.5 pixel offset.
New behaviour - text positioned at 0.5 pixel offset **without** position rounding
Old behaviour - text positioned at 0.5 pixel offset **with** position rounding
  • SDF glyphs are rendered on the GPU by default. This has a positive effect on the performance, as well as on the visual fidelity when text is rendered on fractional coordinates. The developer option --allowSDFonGPU now becomes --disableSDFonGPU. With that, to restore the old behavior of the rendering library (SDF glyphs rendered on the CPU), the option --disableSDFonGPU needs to be used.
  • The threshold for using SDF instead of raster rendering of fonts is set to 10 (previously 18). The GPU rendering algorithm for SDF allows us to use SDF glyphs even at smaller sizes and hence we've adjusted the size threshold that decides how a font is rendered. Till now this threshold has been a constant value but now it can be adjusted through the developer option --sdfTextSizeThreshold. The old behavior of the rendering library can be restored when the option is used like --sdfTextSizeThreshold 18. To note is that this change also affects the font hinting for font sizes between 10 and 18. As a consequence, the effective width of some letters can change. The images below show the text rendering with the old and new default values.
Text rendering with the old system defaults
Text rendering with the new system defaults
  • SDF glyphs are now rendered onto 16-bit textures by default. Previously the glyphs were rendered on 8-bit textures, but this can lead to inconsistent visual results because of rounding errors on the GPU during interpolation. Therefore, a glyph can look different when it's in different places in the glyph atlas. To note is, however, that the difference is barely noticeable. 16-bit textures solve this problem but consume twice as much memory. The old behavior for the SDF rendered on the GPU can be brought back with the developer option --8bitGPUSDFTextures. To note is that if the 8-bit textures are in use, the provided shaders have to be recompiled with the define USE_8BIT_GPUSDF_ATLASES 1.
  • Because of the previous change, we also introduce a new pixel format in our rendering library - renoir::PF_R16. The format is meant to represent 16-bit unsigned normalized values. That is, textures created with this format are R16Unorm. In the backends, the 16-bit textures are created with this format. The one exception to this is the GLES2 backend, where only 8-bit textures are created regardless of the renoir::PF_R16 format.

Important The PS4 and PS5 backends create R16Float textures for the renoir::PF_R16 format because of a known blending issue with R16Unorm textures on these platforms.

  • The pixel format renoir::PF_A8 is removed in favor of renoir::PF_R8. With that, all of the shaders and the backends are adjusted.
  • The ST_TextSDFGPU shader type is moved to the standard pixel shader - CohStandardPS.hlsl. The mappings in the backends are adjusted as well.
  • Added optional multi-sampling for the ST_TextSDFGPU shader type. The code for drawing glyphs from a GPU-generated SDF atlas is in CohShadeGeometry.ihlsl. If the define COH_ALLOW_SS is present in the file during shader compilation, the multi-sampling is enabled. By default it is disabled. The multi-sampling does 4 samples of the glyph atlas to increase the quality of the rendered text at small font sizes - 14 and lower - but it also has a negative performance impact.

Rendering changes summary

As there are quite a few changes to the rendering pipeline, we'll summarize in several steps what is to be done in the client code

  • Remove the ST_ClearQuadWithDepth shader type as it does not exist anymore.
  • The ST_TextSDFGPU shader type is not handled in the standard shader so the backend mappings have to be adjusted
  • The format renoir::PF_A8 is now renoir::PF_R8 so the backends and shaders have to be adjusted to handle it.
  • The new format renoir::PF_R16 is introduced so the backends should be able to create R16Unorm textures for it.

Transition to Prysm 1.17.0

  • The renoir::Texture2D structure is changed so that the renoir::Texture2D::WillNeverOverwrite field is removed. Textures that will be changed are marked with renoir::IMP_Dynamic in their renoir::Texture2D::Props field.
  • A new texture flag for the renoir::Texture2D::Props field is introduced – renoir::IMP_InvertAlpha. Textures with this flags are considered with inverted alpha and Renoir will handle them correctly if they need to be drawn. The new image property can also be used for the renoir::ImageInfo::Props field.

Transition to Prysm 1.18.0

  • In previous versions the LibraryParams::AllowMultipleRenderingThreads was always enabled, now it'll be off by default. From 1.18.0 the option must be enabled during Library initialization if the game engine has multiple rendering threads to disable incorrect asserts.

Transition to Prysm

  • The PS4 and PS5 shaders have to be compiled with the -indirect-draw flag as Renoir now uses features that require it. The command line options can be passed both to orbis-wave-psslc.exe and prospero-wave-psslc.exe shader compilers.
  • There is a new field in the renoir::RendererCaps structure - SupportsSharedIndexBuffers. The field indicates whether the backend supports using the same index buffer with multiple vertex buffers. In almost all cases this is true, but the Unity C# backend does not support this.

Transition to Prysm 1.22.0

  • In this version, we've added a scratch texture atlasing feature which required small changes in the shaders. In some cases, we might need to use the constant buffer PrimProps1 as a scissor rectangle for sampling from an input image. The changes are in CohShadeGeometry.ihlsl, CohShadeGeometryBatched.ihlsl and CohShadeGeometryRare.ihlsl, so you should rebuild shaders, or copy them from the corresponding platform package. No backend changes are required.

Transition to Prysm 1.25

Anti-aliased clipping

Version 1.25 of Prysm introduces anti-aliased clipping (for more details see Anti-Aliased Clipping). This has required some changes to the rendering.

  • All backends now support 5 texture slots instead of 4.
  • The PerPrimitivePS constant buffer now has a new int field ShouldClip.
  • There is a new pixel shader – CohClipMaskPS.hlsl
  • There are a few new pixel shader types (renoir::PixelShaderTypes). renoir::PixelShaderTypes::PST_ClippingRect – used for drawing a clip rectangle, renoir::PixelShaderTypes::PST_ClippingCircle – used to drawing clip circle, renoir::PixelShaderTypes::PST_ClippingTexture – used for drawing clip image, and renoir::PixelShaderTypes::PST_ClippingPath – used to draw a clip-path. The handling of these shader types is in the new CohClipMaskPS.hlsl pixel shader.
  • There are a few new shader types that all backends are being able to handle – renoir::ShaderType::ST_Clipping, renoir::ShaderType::ST_ClippingRect, renoir::ShaderType::ST_ClippingCircle, renoir::ShaderType::ST_ClippingTexture, and renoir::ShaderType::ST_Clipping::ST_ClippingPath. The handling of these shader types can be seen in the renoir::Dx11Backend backend.

Enhancement of user fonts API

Previously, the cohtml::UserFontDescription structure contained a Baseline field, which divided the line height into 2 parts. In version 1.25 this field is removed in favor of adding 2 different ones - Ascent and Descent, which are produced by most font authoring tools and provide greater control for the glyph positioning. The Ascent is the part above the baseline and the Descent is the part below. These 2 values may not sum up to the LineHeight - the excess height is the line gap, which is used internally for proper positioning.

The samples and documentation are updated to reflect this change.

  • If the tool you're using for generating user fonts outputs the Ascent and Descent, you can directly use them (ascent is positive and descent is negative).
  • If you don't have those values readily available, you can do an approximation that assumes no line gap using the Baseline value:
    • Ascent = Baseline
    • Descent = Baseline - LineHeight

Compositor API Enhancement

Version 1.25 of Prysm introduces enhancement of the usage of Compositor (see Compositor).

  • unsigned ViewId is added to the renoir::ISublayerCompositor::DrawData structure. With this change, you can have the same composition IDs in different views.
  • Likewise, unsigned viewId is added as a parameter to OnCompositionRemoved callback to identify the actual composition for removal

New rendering backend capability

  • There is a new field in the renoir::RendererCaps structure - EndingRenderPassRequiresStateUpdate. The field indicates whether the GPU state should rebound after a render pass has been ended. This is a requirement for some graphics APIs (e.g. Metal) where the driver requires you to update the GPU pipeline state every time after the end of a render pass. The EndingRenderPassRequiresStateUpdate has been added in order not to burden the backend themselves to cache the GPU state and rebind it again after a render pass ends.

Transition to Prysm 1.26

Deprecation of the IAsyncResourceResponse::UserImageData::TextureFilteringMode enumeration

The IAsyncResourceResponse::UserImageData::TextureFilteringMode enumeration is deprecated and its usage is discouraged, as it may soon be removed.

Creators should instead use the newly supported CSS property image-rendering, which allows for controlling the same functionality but for each image instance, not each image resource, offering greater flexibility. The image-rendering property supports 3 values: auto, crisp-edges and pixelated. The current implementation uses a linear sampler for auto and a point sampler for crisp-edges and pixelated.

Transition to Prysm 1.27

Changed enumerations naming

In this version to add more consistency in naming between shaders and C++ code, we made some changes in CBType (for available Constant Buffers) and ShaderType (for available shaders) enumerations.

In CBType:

// Vertex constant buffers
CB_Transforms -> CB_TransformVS
CB_RenoirShaderVS -> CB_RenoirShaderParamsVS
// Pixel constant buffers
CB_GlobalPixel -> CB_GlobalDataPS
CB_StandardPrimitivePixel -> CB_StandardPrimitivePS
CB_StandardPrimitiveAdditionalPixel -> CB_StandardPrimitiveAdditionalPS
CB_EffectsPixel -> CB_EffectsPS
CB_RenoirShaderPS -> CB_RenoirShaderParamsPS

In ShaderType

ST_BatchedStandard -> ST_StandardBatched
ST_BatchedStandardTexture -> ST_StandardBatchedTexture
ST_TexturesWithColorMix -> ST_ColorMixing
ST_GenerateSDFOutline -> ST_GenerateSDF
ST_Clipping -> ST_ClipMask

We have changed the naming of the constant buffers in the shaders in order to be consistent with the enumerations, so you should get the latest shaders to run the latest backend.

Constant buffer usage optimization

Sometimes before some draws there might be constant buffer updates which actually are not used at all in the current draw. We wanted to optimize those cases, so we've implemented a feature which updates the constant buffer only if it exists in the shader in the next draw.

It will work only with the default mapping in backend's FillCaps method. If you have any changes to this mapping please use our developer option --disableCBUpdateOptimization to disable the optimization. Otherwise, you will not receive all constant buffer updates correctly.

Transition to Prysm 1.28

Changed API for ICustomEffectHandler

In order for the ICustomEffectHandler to work for all the platforms, data should be transferred for some rendering APIs between the backend and the handler implementation. For this reason, we've changed the OnDrawCustomEffect callback which now takes void as its second parameter. The data is filled in the corresponding backend's function DrawCustomEffect. In the cases when the parameter is nullptr, that means that no data from the backend is required to execute the draw call.

There was another requirement for some rendering APIs, where the rendering pass should be finished when the constant buffers are updated. So, we've implemented another callback OnPrepareConstantBufferData which is called on platforms with specifics in the update of the constant buffers' GPU data. You can check ICustomEffectHandler's definition in BaseBackend.h to read more about this callback. Also check the implementation of DrawCustomEffect in VulkanBackend.cpp.