blob: 7b783e5811dbab4549d5a0c11e81538838cf673b [file]
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <gui/LocklessStaticQueue.h>
#include <gui/MagicRingBuffer.h>
#include <log/log.h>
#include <atomic>
#include <string>
#include "RPointer.h"
constexpr int RENDER_COMMAND_BUFFER_DEFAULT_SIZE = 1024 * 1024;
constexpr bool RENDER_COMMAND_BUFFER_VERBOSE = false;
namespace android {
struct IPCRenderBufferOp {
RPointer<IPCRenderBufferOp> next;
uint32_t type;
};
struct IPCRenderBufferUploadOp : public MagicRingBufferEntry {
uint32_t type;
};
template <size_t Size>
struct IpcArena {
IpcArena() { memset(mBytes, 0, sizeof(mBytes)); }
uint8_t mBytes[Size];
size_t mUsed = 0;
static size_t roundUp(size_t n, size_t m) { return ((n + m - 1) / m) * m; }
template <typename T>
T* allocAligned(size_t count = 1) {
size_t aligned = roundUp(mUsed, alignof(T));
size_t allocationSize = count * sizeof(T);
if (aligned + allocationSize > sizeof(mBytes)) {
return nullptr;
}
uint8_t* ptr = mBytes + aligned;
mUsed = aligned + allocationSize;
return reinterpret_cast<T*>(ptr);
}
void resetArena() { mUsed = 0; }
};
template <typename T, typename A>
inline bool SetRSpan(RSpan<T>& span, A* allocator, const T* data, size_t count) {
span.data = allocator->template allocAligned<T>(count);
if (!span.data) {
return false;
}
span.size = count;
if (data) {
memcpy(span.data.get(), data, count * sizeof(T));
}
return true;
}
struct IpcRenderRegion;
class RenderCommandBuffer : public IpcArena<RENDER_COMMAND_BUFFER_DEFAULT_SIZE> {
public:
RenderCommandBuffer() {}
~RenderCommandBuffer() {}
RPointer<IpcRenderRegion> mRegion;
IPCRenderBufferOp* getOps() { return mHead.get(); }
// op must be allocated by this RenderCommandBuffer
void pushOp(IPCRenderBufferOp* op);
void reset();
bool dumpToFile(const char* filename) const;
static RenderCommandBuffer* loadFromFile(const char* filename);
void setFrameSize(int width, int height) {
mWidth = width;
mHeight = height;
}
void getFrameSize(int& width, int& height) {
width = mWidth;
height = mHeight;
}
RPointer<IPCRenderBufferOp> mTail;
RPointer<IPCRenderBufferOp> mHead;
// These are somewhat awkward, and used to achieve compatibility with the buffer based geometry
// calculations. Effectively this is the size that the buffer would have been in the normal
// rendering mode.
int mWidth = 0;
int mHeight = 0;
};
struct IpcRenderRegion {
LocklessStaticQueue<RenderCommandBuffer, 4> mCommandBuffers;
std::atomic<uint64_t> mFrameNumber;
MagicRingBuffer<16 * 1024 * 1024> mUploadBuf;
template <typename T>
T* allocAligned(size_t count = 1) {
return mUploadBuf.append<T>(count);
}
};
} // namespace android