DMA Offscreen Buffer Example The example demonstrates a realistic usecase of DMA offscreen buffers, where a stream texture provided by a wayland client to the embedded compositor gets processed on CPU side and the result image is calculated on CPU.
The example creates the following setup: A renderer with four DMA OBs and two local scenes:
#include <unordered_set>
#include <unordered_map>
#include <thread>
#include <cstring>
#include <sys/mman.h>
#include <unistd.h>
#include "linux/dma-buf.h"
#include "linux/ioctl.h"
#include <sys/ioctl.h>
#include <drm_fourcc.h>
#include <gbm.h>
static constexpr uint32_t OffscreenBufferWidth = 200u;
static constexpr uint32_t OffscreenBufferHeight = 200u;
static constexpr uint32_t DmaBufferFourccFormat = DRM_FORMAT_ARGB8888;
static constexpr std::chrono::seconds ExampleRunDuration{ 60u };
static constexpr bool ExampleTakeScreenshots = false;
#version 300 es
in lowp vec3 a_position;
in lowp vec2 a_texcoord;
out lowp vec2 v_texcoord;
uniform lowp mat4 mvpMatrix;
void main()
{
v_texcoord = a_texcoord;
gl_Position = mvpMatrix * vec4(a_position, 1.0);
}
)##";
#version 300 es
uniform sampler2D textureSampler;
in lowp vec2 v_texcoord;
out lowp vec4 fragColor;
void main(void)
{
fragColor = texture(textureSampler, v_texcoord);
}
)##";
{
public:
: m_renderer(renderer)
{
}
{
{
static uint32_t filePostifx = 0u;
const std::string fileName = "./dmaBufExampleScreenshot_" + std::to_string(filePostifx++) + ".png";
printf("Error: Failed saving screenshot to %s !!\n", fileName.c_str());
else
printf("Saved screenshot to %s\n", fileName.c_str());
}
else
printf("Error: Failed read pixels!!\n");
}
{
m_scenes[sceneId].state = state;
}
{
{
m_createdDisplays.insert(displayId);
}
}
{
{
m_createdOffscreenBuffers.insert(offscreenBufferId);
}
}
{
if (success)
{
}
}
{
waitForElementInSet(displayId, m_createdDisplays);
}
{
waitForElementInSet(offscreenBufferId, m_createdOffscreenBuffers);
}
{
waitUntilOrTimeout([&] {return m_scenesConsumingOffscreenBuffer.count(sceneId) > 0; });
}
{
waitUntilOrTimeout([&] { return m_scenes[sceneId].state == state; });
}
bool waitUntilOrTimeout(const std::function<bool()>& conditionFunction)
{
const std::chrono::steady_clock::time_point timeoutTS = std::chrono::steady_clock::now() + std::chrono::seconds{ 5 };
while (!conditionFunction() && std::chrono::steady_clock::now() < timeoutTS)
{
}
const auto result = conditionFunction();
if(!result)
printf("Error: timed out waiting for state/condition!\n");
return result;
}
private:
struct SceneInfo
{
};
using SceneSet = std::unordered_map<ramses::sceneId_t, SceneInfo>;
using DataConsumerSet = std::unordered_set<ramses::dataConsumerId_t>;
using DisplaySet = std::unordered_set<ramses::displayId_t>;
using OffscreenBufferSet = std::unordered_set<ramses::displayBufferId_t>;
template <typename T>
void waitForElementInSet(const T element, const std::unordered_set<T>& set)
{
while (set.find(element) == set.end())
{
std::this_thread::sleep_for(std::chrono::milliseconds(10u));
}
}
SceneSet m_scenes;
SceneSet m_scenesAssignedToOffscreenBuffer;
SceneSet m_scenesConsumingOffscreenBuffer;
DisplaySet m_createdDisplays;
OffscreenBufferSet m_createdOffscreenBuffers;
DataConsumerSet m_dataConsumers;
};
{
}
{
const uint16_t indicesArray[] = { 0, 1, 2, 2, 1, 3 };
const float vertexPositionsArray[] =
{
-1.f, -1.f, 0.f,
1.f, -1.f, 0.f,
-1.f, 1.f, 0.f,
1.f, 1.f, 0.f
};
const float textureCoordsArray[] = { 0.f, 1.f, 1.f, 1.f, 0.f, 0.f, 1.f, 0.f };
return *meshNode;
}
{
camera->
setFrustum(-2.f, 2.f, -2.f, 2.f, 0.1f, 100.f);
streamTexture,
"mainSceneStreamTexSampler");
meshCompositedTexture.setTranslation(-1.f, 0.f, 0.f);
fallbackTexture,
1u,
processingOutputSamplerName.c_str());
meshOutputTexture.setTranslation(1.f, 0.f, 0.f);
return *clientScene;
}
{
camera->
setFrustum(-1.f, 1.f, -1.f, 1.f, 0.1f, 100.f);
camera->
setViewport(0, 0u, OffscreenBufferWidth, OffscreenBufferHeight);
streamTexture,
"source stream tex sampler");
return *clientScene;
}
{
};
std::unordered_map<ramses::displayBufferId_t, BufferInfo>
bufferInfoMap;
{
constexpr uint32_t usageFlags = GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT;
constexpr uint64_t modifier = DRM_FORMAT_MOD_INVALID;
const auto bufferId = renderer.
createDmaOffscreenBuffer(display, OffscreenBufferWidth, OffscreenBufferHeight, DmaBufferFourccFormat, usageFlags, modifier);
if(!bufferId.isValid())
printf("Error: Failed creating offscreen buffer!\n");
return bufferId;
}
{
errno = 0;
{
printf("Error: Buffer already mapped!\n");
return false;
}
int bufferFD = -1;
uint32_t bufferStride = 0;
{
printf("Error: Failed to get FD and stride!\n");
return false;
}
const std::size_t fileSize = static_cast<std::size_t>(lseek(bufferFD, 0u, SEEK_END));
const auto mappingPreviliges = (readyOnly? (PROT_READ) : (PROT_WRITE | PROT_READ));
void* mappedMemory = mmap(nullptr, fileSize, mappingPreviliges, MAP_SHARED, bufferFD, 0u);
if(mappedMemory == MAP_FAILED)
{
const auto errorValue = errno;
printf("Error: Failed to map memory (errno=%i, errnoString=%s)!\n", errorValue, strerror(errorValue));
return false;
}
printf(
"Mapped OB %u with FD %i successfully to %p\n", displayBuffer.
getValue(), bufferFD, mappedMemory);
bufferInfoMap[displayBuffer] = {bufferFD, bufferStride, fileSize, mappedMemory};
return true;
}
{
{
printf("Error: Failed to find buffer for start sync!\n");
return false;
}
dma_buf_sync syncStartFlags = { 0 };
syncStartFlags.flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_RW;
const auto syncStartResult = ioctl(bufferInfoIt->second.fd, DMA_BUF_IOCTL_SYNC, &syncStartFlags);
if(syncStartResult != 0)
{
printf("Error: Failed to start sync!\n");
return false;
}
return true;
}
{
{
printf("Error: Failed to find buffer for end sync!\n");
return false;
}
dma_buf_sync syncEndFlags = { 0 };
syncEndFlags.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_RW;
const auto syncEndResult = ioctl(bufferInfoIt->second.fd, DMA_BUF_IOCTL_SYNC, &syncEndFlags);
if(syncEndResult != 0)
{
printf("Failed to end sync!\n");
return false;
}
return true;
}
{
const auto& inputBufferInfo =
bufferInfoMap.find(inputBuffer)->second;
const auto& outputBufferInfo =
bufferInfoMap.find(outputBuffer)->second;
const auto bufferStride = inputBufferInfo.stride;
return false;
return false;
for(uint32_t row = 0u; row < OffscreenBufferHeight; ++row)
{
for(uint32_t col = 0u; col < OffscreenBufferWidth; ++col)
{
uint8_t* inputPixelMem = reinterpret_cast<uint8_t*>(inputBufferInfo.mappedMem) + row * bufferStride + col * 4u;
uint8_t* outputPixelMem = reinterpret_cast<uint8_t*>(outputBufferInfo.mappedMem) + row * bufferStride + col * 4u;
const float magicValue1 = 1.f * col / OffscreenBufferWidth;
const uint16_t magicValue2 = uint8_t(255.f * col / OffscreenBufferWidth);
const uint8_t magicValue3 = uint8_t(255.f * row / OffscreenBufferHeight);
switch (DmaBufferFourccFormat)
{
case DRM_FORMAT_ARGB8888:
outputPixelMem[0] = inputPixelMem[0];
outputPixelMem[1] = std::min<uint8_t>(uint8_t(magicValue1 * inputPixelMem[1]), 255u);
outputPixelMem[2] = uint8_t(std::min<uint16_t>(magicValue2 + inputPixelMem[2], 255u));
outputPixelMem[3] = magicValue3;
break;
default:
printf("Error: Unsupported format!\n");
return false;
}
}
}
return false;
return false;
return true;
}
int main(
int argc,
char* argv[])
{
rendererConfig.setFrameCallbackMaxPollTime(66000);
framework.connect();
displayConfig.setPlatformRenderNode("/dev/dri/renderD128");
eventHandler.waitForDisplayCreated(display);
eventHandler.waitForOffscreenBufferCreated(dmaOffscreenBufferRead1);
eventHandler.waitForOffscreenBufferCreated(dmaOffscreenBufferRead2);
eventHandler.waitForOffscreenBufferCreated(dmaOffscreenBufferWrite1);
eventHandler.waitForOffscreenBufferCreated(dmaOffscreenBufferWrite2);
return 1;
return 1;
return 1;
return 1;
printf("\n************* All OBs mapped successfully !! **********\n");
const std::string& processingOutputSamplerName = "processingOutputTexSampler";
sceneControlAPI.setSceneMapping(mainSceneId, display);
sceneControlAPI.flush();
sceneControlAPI.setSceneMapping(sourceSceneId, display);
sceneControlAPI.setSceneDisplayBufferAssignment(sourceSceneId, backDMAReadBufferId);
sceneControlAPI.flush();
const auto exampleStartTime = std::chrono::steady_clock::now();
while ((std::chrono::steady_clock::now() - exampleStartTime) < ExampleRunDuration)
{
if(ExampleTakeScreenshots)
{
}
sceneControlAPI.setSceneDisplayBufferAssignment(sourceSceneId, backDMAReadBufferId);
sceneControlAPI.linkOffscreenBuffer(backDMAWriteBufferId, mainSceneId, samplerConsumerId);
sceneControlAPI.flush();
std::swap(backDMAReadBufferId, frontDmaReadBufferId);
std::swap(backDMAWriteBufferId, frontDmaWriteBufferId);
}
{
errno = 0;
const auto result = munmap(bufferInfo.second.mappedMem, bufferInfo.second.bufferSize);
if(result == -1)
{
const auto errorValue = errno;
printf("Error: Failed to unmap memory for OB %u (errno=%i, errnoString=%s)!\n", bufferInfo.first.getValue(), errorValue, strerror(errorValue));
return 1;
}
printf("Unmapped OB %u with FD %i successfully!\n", bufferInfo.first.getValue(), bufferInfo.second.fd);
}
printf("\n************* All OBs unmapped successfully !! **********\n");
return 0;
}
SceneStateEventHandler(ramses::RendererSceneControl &sceneControlApi, ramses::RamsesRenderer &renderer)
Definition: main.cpp:50
The Appearance describes how an object should look like. This includes GLSL uniform values,...
Definition: Appearance.h:34
status_t setInputTexture(const UniformInput &input, const TextureSampler &textureSampler)
Sets texture sampler to the input.
The ArrayResource stores a data array of a given type. The data is immutable. The resource can be use...
Definition: ArrayResource.h:26
status_t setViewport(int32_t x, int32_t y, uint32_t width, uint32_t height)
Sets the viewport to be used when rendering with this camera.
status_t setFrustum(float leftPlane, float rightPlane, float bottomPlane, float topPlane, float nearPlane, float farPlane)
Sets camera frustum planes of the Camera.
The DisplayConfig holds a set of parameters to be used to initialize a display.
Definition: DisplayConfig.h:22
An effect description holds all necessary information for an effect to be created.
Definition: EffectDescription.h:21
status_t setVertexShader(const char *shaderSource)
Sets vertex shader source from string.
status_t setFragmentShader(const char *shaderSource)
Sets fragment shader source from string.
status_t setUniformSemantic(const char *inputName, EEffectUniformSemantic semanticType)
Sets an uniform semantic. Used for uniforms which are not locally available on the client,...
An effect describes how an object will be rendered to the screen.
Definition: Effect.h:26
status_t findUniformInput(const char *inputName, UniformInput &uniformInput) const
Finds uniform input by input name.
status_t findAttributeInput(const char *inputName, AttributeInput &attributeInput) const
Finds attribute input by input name.
A geometry binding together with an appearance describe how an object will be rendered to the screen.
Definition: GeometryBinding.h:25
status_t setIndices(const ArrayResource &indicesResource)
Assign a data array with data type UInt16 or UInt32 to be used when accessing vertex data.
status_t setInputBuffer(const AttributeInput &attributeInput, const ArrayResource &arrayResource, uint32_t instancingDivisor=0)
Assign a data array resource to a given effect attribute input.
The MeshNode holds all information which is needed to render an object to the screen.
Definition: MeshNode.h:25
status_t setAppearance(Appearance &appearance)
Sets the Appearance of the MeshNode.
status_t setGeometryBinding(GeometryBinding &geometry)
Sets the GeometryBinding of the MeshNode.
status_t setTranslation(float x, float y, float z)
Sets the absolute translation the absolute values.
The OrthographicCamera is a local camera which defines an orthographic view into the scene.
Definition: OrthographicCamera.h:22
Entry point of RAMSES client API.
Definition: RamsesClient.h:34
Scene * createScene(sceneId_t sceneId, const SceneConfig &sceneConfig=SceneConfig(), const char *name=nullptr)
Create a new empty Scene.
The RamsesFrameworkConfig holds a set of parameters to be used to initialize ramses.
Definition: RamsesFrameworkConfig.h:23
Class representing ramses framework components that are needed to initialize an instance of ramses cl...
Definition: RamsesFramework.h:35
RamsesRenderer is the main renderer component which provides API to configure and control the way con...
Definition: RamsesRenderer.h:37
status_t setSkippingOfUnmodifiedBuffers(bool enable=true)
Enable or disable skipping of rendering of unmodified buffers. By default the renderer does not re-re...
displayId_t createDisplay(const DisplayConfig &config)
Creates a display based on provided display config. Creation of a display is an asynchronous action a...
status_t flush()
Submits renderer commands (API calls on this instance of RamsesRenderer) since previous flush to be e...
status_t dispatchEvents(IRendererEventHandler &rendererEventHandler)
Most RamsesRenderer methods push commands to an internal queue which is submitted when calling Ramses...
status_t readPixels(displayId_t displayId, displayBufferId_t displayBuffer, uint32_t x, uint32_t y, uint32_t width, uint32_t height)
Triggers an asynchronous read back of a display buffer memory from GPU to system memory.
status_t doOneLoop()
Prepare content to be rendered in next frame and render next frame.
displayBufferId_t createDmaOffscreenBuffer(displayId_t display, uint32_t width, uint32_t height, uint32_t bufferFourccFormat, uint32_t usageFlags, uint64_t modifier)
Additional API to create an offscreen buffer using DMA buffer for internal storage....
status_t getDmaOffscreenBufferFDAndStride(displayId_t display, displayBufferId_t displayBufferId, int &fd, uint32_t &stride) const
Get the FD and stride for a DMA offscreen buffer previously created on the given display.
static status_t setDisplayBufferClearFlags(RamsesRenderer &renderer, displayId_t display, displayBufferId_t displayBuffer, uint32_t clearFlags)
Sets clear flags for a display buffer (display's framebuffer or offscreen buffer).
RendererSceneControl * getSceneControlAPI()
Get scene control API.
displayBufferId_t getDisplayFramebuffer(displayId_t displayId) const
Get display's framebuffer ID. Every display upon creation has one framebuffer which can be referenced...
static bool SaveImageBufferToPng(const std::string &filePath, const std::vector< uint8_t > &imageData, uint32_t width, uint32_t height)
Creates a png from image data, e.g. data generated by RamsesClientService::readPixels....
static Texture2D * CreateTextureResourceFromPng(const char *pngFilePath, Scene &scene, const TextureSwizzle &swizzle={}, const char *name=nullptr)
Creates a Texture from the given png file.
The RenderGroup is a container used to collect renderables which are supposed to be rendered together...
Definition: RenderGroup.h:31
status_t addMeshNode(const MeshNode &mesh, int32_t orderWithinGroup=0)
Add a mesh to this RenderGroup. If a mesh is already contained in this RenderGroup only its render or...
The RenderPass is a container used to collect meshes which are supposed to be rendered together.
Definition: RenderPass.h:31
status_t setCamera(const Camera &camera)
Set the camera to use for rendering the objects of this renderpass.
status_t addRenderGroup(const RenderGroup &renderGroup, int32_t orderWithinPass=0)
Add a RenderGroup to this RenderPass for rendering.
The RendererConfig holds a set of parameters to be used to initialize a renderer.
Definition: RendererConfig.h:26
Convenience empty implementation of IRendererEventHandler that can be used to derive from when only s...
Definition: IRendererEventHandler.h:194
Convenience empty implementation of IRendererSceneControlEventHandler that can be used to derive from...
Definition: IRendererSceneControlEventHandler.h:214
virtual void offscreenBufferLinked(displayBufferId_t offscreenBufferId, sceneId_t consumerScene, dataConsumerId_t consumerId, bool success) override
This method will be called when the data link between offscreen buffer and scene's data slot is estab...
Definition: IRendererSceneControlEventHandler.h:228
virtual void sceneStateChanged(sceneId_t sceneId, RendererSceneState state) override
This method will be called when state of a scene changes.
Definition: IRendererSceneControlEventHandler.h:219
status_t dispatchEvents(IRendererSceneControlEventHandler &eventHandler)
RendererSceneControl methods push commands to an internal queue which is submitted when calling flush...
The SceneConfig holds a set of parameters to be used when creating a scene.
Definition: SceneConfig.h:22
The Scene holds a scene graph. It is the essential class for distributing content to the ramses syste...
Definition: Scene.h:83
OrthographicCamera * createOrthographicCamera(const char *name=nullptr)
Creates a Orthographic Camera in this Scene.
MeshNode * createMeshNode(const char *name=nullptr)
Creates a scene graph MeshNode. MeshNode is a Node with additional properties and bindings that repre...
Effect * createEffect(const EffectDescription &effectDesc, resourceCacheFlag_t cacheFlag=ResourceCacheFlag_DoNotCache, const char *name=nullptr)
Create a new Effect by parsing a GLSL shader described by an EffectDescription instance....
GeometryBinding * createGeometryBinding(const Effect &effect, const char *name=nullptr)
Creates a new GeometryBinding.
ArrayResource * createArrayResource(EDataType type, uint32_t numElements, const void *arrayData, resourceCacheFlag_t cacheFlag=ResourceCacheFlag_DoNotCache, const char *name=nullptr)
Create a new ArrayResource. It makes a copy of the given data of a certain type as a resource,...
status_t publish(EScenePublicationMode publicationMode=EScenePublicationMode_LocalAndRemote)
Publishes the scene to the ramses system.
RenderPass * createRenderPass(const char *name=nullptr)
Create a render pass in the scene.
Appearance * createAppearance(const Effect &effect, const char *name=nullptr)
Creates a new Appearance.
StreamTexture * createStreamTexture(const Texture2D &fallbackTexture, waylandIviSurfaceId_t source, const char *name=nullptr)
Create a Stream Texture.
RenderGroup * createRenderGroup(const char *name=nullptr)
Create a RenderGroup instance in the scene.
const RamsesObject * findObjectByName(const char *name) const
Get an object from the scene by name.
status_t flush(sceneVersionTag_t sceneVersionTag=InvalidSceneVersionTag)
Commits all changes done to the scene since the last flush or since scene creation....
TextureSampler * createTextureSampler(ETextureAddressMode wrapUMode, ETextureAddressMode wrapVMode, ETextureSamplingMethod minSamplingMethod, ETextureSamplingMethod magSamplingMethod, const Texture2D &texture, uint32_t anisotropyLevel=1, const char *name=nullptr)
Creates a texture sampler object.
status_t createTextureConsumer(const TextureSampler &sampler, dataConsumerId_t dataId)
Annotates a ramses::TextureSampler as a content consumer. Texture provider and texture consumer can b...
StreamTexture is a special kind of texture, which holds a reference to a "fallback texture" and a str...
Definition: StreamTexture.h:25
Helper class to create strongly typed values out of various types.
Definition: StronglyTypedValue.h:23
constexpr BaseType getValue() const
Getter for retrieving the underlying value.
Definition: StronglyTypedValue.h:73
Texture represents a 2-D texture resource.
Definition: Texture2D.h:24
The TextureSampler holds a texture and its sampling parameters.
Definition: TextureSampler.h:29
@ ETextureSamplingMethod_Linear
Definition: TextureEnums.h:21
@ ETextureAddressMode_Repeat
Definition: TextureEnums.h:33
@ EClearFlags_None
Definition: RamsesFrameworkTypes.h:257
@ ModelViewProjectionMatrix
Model-view-projection matrix 4x4.
@ Vector2F
two components of type float per data element
@ UInt16
one component of type uint16_t per data element
@ Vector3F
three components of type float per data element
RendererSceneState
Definition: RendererSceneState.h:19
@ Unavailable
Scene is unavailable, no scene control possible.
@ Rendered
Scene is being rendered.
constexpr const status_t StatusOK
Status returned from RAMSES client API methods that succeeded.
Definition: RamsesFrameworkTypes.h:32
constexpr const resourceCacheFlag_t ResourceCacheFlag_DoNotCache
Requests the render to not cache a resource. This is the default value.
Definition: RamsesFrameworkTypes.h:212
uint64_t sceneVersionTag_t
Scene version tag used to refer to content versions of a scene. A scene version may be updated along ...
Definition: RamsesFrameworkTypes.h:49
ERendererEventResult
Specifies the result of the operation referred to by renderer event.
Definition: Types.h:94
@ ERendererEventResult_OK
Event referring to an operation that succeeded.
Definition: Types.h:95
@ ERendererEventResult_FAIL
Event referring to an operation that failed.
Definition: Types.h:97
constexpr const sceneVersionTag_t InvalidSceneVersionTag
Scene version tag used to refer to an invalid scene version.
Definition: RamsesFrameworkTypes.h:54
int main(int argc, char *argv[])
Definition: main.cpp:21
bool startBufferAccess(ramses::displayBufferId_t displayBuffer)
Definition: main.cpp:403
constexpr const char *const vertexShader
Definition: main.cpp:66
bool endBufferAccess(ramses::displayBufferId_t displayBuffer)
Definition: main.cpp:425
ramses::MeshNode & createQuadWithTexture(ramses::Scene &scene, ramses::Effect &effect, ramses::TextureSampler &textureSampler)
Definition: main.cpp:229
ramses::Scene & createMainScene(ramses::RamsesClient &client, ramses::sceneId_t sceneId, ramses::waylandIviSurfaceId_t streamId, const std::string &processingOutputSamplerName)
Definition: main.cpp:268
ramses::Effect & createEffect(ramses::Scene &scene, const std::string &effectName)
Definition: main.cpp:219
bool mapDmaOffscreenBuffer(ramses::RamsesRenderer &renderer, ramses::displayId_t display, ramses::displayBufferId_t displayBuffer, bool readyOnly)
Definition: main.cpp:370
constexpr const char *const fragmentShader
Definition: main.cpp:80
std::unordered_map< ramses::displayBufferId_t, BufferInfo > bufferInfoMap
Definition: main.cpp:356
ramses::Scene & createSourceScene(ramses::RamsesClient &client, ramses::sceneId_t sceneId, ramses::waylandIviSurfaceId_t streamId)
Definition: main.cpp:316
bool doProcessing(ramses::displayBufferId_t inputBuffer, ramses::displayBufferId_t outputBuffer)
Definition: main.cpp:447
ramses::displayBufferId_t createDmaOffscreenBuffer(ramses::RamsesRenderer &renderer, ramses::displayId_t display)
Definition: main.cpp:358
constexpr uint32_t DisplayWidth
Definition: main.cpp:31
constexpr uint32_t DisplayHeight
Definition: main.cpp:32
int fd
Definition: main.cpp:351
std::size_t bufferSize
Definition: main.cpp:353
void * mappedMem
Definition: main.cpp:354
uint32_t stride
Definition: main.cpp:352