summaryrefslogtreecommitdiffstats
path: root/tools/render-test/surface.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/render-test/surface.cpp')
-rw-r--r--tools/render-test/surface.cpp223
1 files changed, 223 insertions, 0 deletions
diff --git a/tools/render-test/surface.cpp b/tools/render-test/surface.cpp
new file mode 100644
index 000000000..636881fca
--- /dev/null
+++ b/tools/render-test/surface.cpp
@@ -0,0 +1,223 @@
+// surface.cpp
+#include "surface.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "../../source/core/slang-list.h"
+
+namespace gfx {
+using namespace Slang;
+
+class MallocSurfaceAllocator: public SurfaceAllocator
+{
+ public:
+
+ virtual Slang::Result allocate(int width, int height, Format format, int alignment, Surface& surface) override;
+ virtual void deallocate(Surface& surface) override;
+};
+
+static MallocSurfaceAllocator s_mallocSurfaceAllocator;
+
+/// Get the malloc allocator
+/* static */SurfaceAllocator* SurfaceAllocator::getMallocAllocator()
+{
+ return &s_mallocSurfaceAllocator;
+}
+
+Slang::Result MallocSurfaceAllocator::allocate(int width, int height, Format format, int alignment, Surface& surface)
+{
+ assert(surface.m_data == nullptr);
+
+ // Calculate row size
+
+ const int rowSizeInBytes = Surface::calcRowSize(format, width);
+ const int numRows = Surface::calcNumRows(format, height);
+
+ alignment = (alignment <= 0) ? int(sizeof(void*)) : alignment;
+ // It must be a power of 2
+ assert( ((alignment - 1) & alignment) == 0);
+
+ // Align rowSize
+ const int alignedRowSizeInBytes = (rowSizeInBytes + alignment - 1) & -alignment;
+
+ size_t totalSize = numRows * alignedRowSizeInBytes;
+
+ uint8_t* data = (uint8_t*)::malloc(totalSize);
+ if (!data)
+ {
+ return SLANG_E_OUT_OF_MEMORY;
+ }
+
+ surface.m_data = data;
+ surface.m_width = width;
+ surface.m_height = height;
+ surface.m_format = format;
+ surface.m_numRows = numRows;
+ surface.m_rowStrideInBytes = alignedRowSizeInBytes;
+
+ surface.m_allocator = this;
+ return SLANG_OK;
+}
+
+void MallocSurfaceAllocator::deallocate(Surface& surface)
+{
+ assert(surface.m_data);
+ // Make sure it's not an inverted, cos otherwise m_data is not the start address
+ assert(surface.m_rowStrideInBytes > 0);
+ ::free(surface.m_data);
+}
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Surface !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+/* static */int Surface::calcRowSize(Format format, int width)
+{
+ size_t pixelSize = gfxGetFormatSize(format);
+ if (pixelSize == 0)
+ {
+ return 0;
+ }
+ return int(pixelSize * width);
+}
+
+/* static */int Surface::calcNumRows(Format format, int height)
+{
+ // Don't have any compressed types, so number of rows is same as the height
+ return height;
+}
+
+void Surface::init()
+{
+ m_width = 0;
+ m_height = 0;
+ m_format = Format::Unknown;
+ m_data = nullptr;
+ m_numRows = 0;
+ m_rowStrideInBytes = 0;
+ // NOTE! does not clear the allocator.
+ // If called with an allocation memory will leak!
+}
+
+Surface::~Surface()
+{
+ if (m_data && m_allocator)
+ {
+ m_allocator->deallocate(*this);
+ }
+}
+
+void Surface::deallocate()
+{
+ if (m_data && m_allocator)
+ {
+ m_allocator->deallocate(*this);
+ init();
+ }
+}
+
+Result Surface::allocate(int width, int height, Format format, int alignment, SurfaceAllocator* allocator)
+{
+ deallocate();
+ allocator = allocator ? allocator : m_allocator;
+ if (!allocator)
+ {
+ // An allocator needs to be set on the surface, or one passed in.
+ return SLANG_FAIL;
+ }
+ return allocator->allocate(width, height, format, alignment, *this);
+}
+
+void Surface::setUnowned(int width, int height, Format format, int strideInBytes, void* data)
+{
+ deallocate();
+
+ // This is unowned
+ m_allocator = nullptr;
+
+ m_width = width;
+ m_height = height;
+ m_format = format;
+ m_rowStrideInBytes = strideInBytes;
+ m_data = (uint8_t*)data;
+
+ m_numRows = Surface::calcNumRows(format, height);
+
+ const int rowSizeInBytes = Surface::calcRowSize(format, width);
+ assert((strideInBytes > 0 && rowSizeInBytes <= strideInBytes) || (strideInBytes < 0 && rowSizeInBytes <= -strideInBytes));
+}
+
+void Surface::zeroContents()
+{
+ const int rowSizeInBytes = Surface::calcRowSize(m_format, m_width);
+
+ const int stride = m_rowStrideInBytes;
+ uint8_t* dst = m_data;
+
+ for (int i = 0; i < m_numRows; i++, dst += stride)
+ {
+ ::memset(dst, 0, rowSizeInBytes);
+ }
+}
+
+void Surface::flipInplaceVertically()
+{
+ // Can only flip when m_height matches number of rows
+ assert(m_numRows == m_height);
+
+ const int rowSizeInBytes = Surface::calcRowSize(m_format, m_width);
+ if (rowSizeInBytes <= 0 || m_numRows <= 1)
+ {
+ return;
+ }
+
+ uint8_t* top = m_data;
+ uint8_t* bottom = m_data + (m_numRows - 1) * m_rowStrideInBytes;
+
+ List<uint8_t> bufferList;
+ bufferList.setCount(rowSizeInBytes);
+ uint8_t* buffer = bufferList.getBuffer();
+
+ const int stride = m_rowStrideInBytes;
+
+ const int num = m_height >> 1;
+ for (int i = 0; i < num; ++i, top += stride, bottom -= stride)
+ {
+ ::memcpy(buffer, top, rowSizeInBytes);
+ ::memcpy(top, bottom, rowSizeInBytes);
+ ::memcpy(bottom, buffer, rowSizeInBytes);
+ }
+}
+
+SlangResult Surface::set(int width, int height, Format format, int srcRowStride, const void* data, SurfaceAllocator* allocator)
+{
+ if (hasContents() && m_width == width && m_height == height && m_format == format)
+ {
+ // I can just overwrite the contents that is there
+ }
+ else
+ {
+ SLANG_RETURN_ON_FAIL(allocate(width, height, format, 0, allocator));
+ }
+
+ // Okay just need to set the contents
+
+ {
+ const size_t rowSize = calcRowSize(format, width);
+
+ const uint8_t* srcRow = (const uint8_t*)data;
+ uint8_t* dstRow = (uint8_t*)m_data;
+
+ for (int i = 0; i < m_numRows; i++)
+ {
+ ::memcpy(dstRow, srcRow, rowSize);
+
+ srcRow += srcRowStride;
+ dstRow += m_rowStrideInBytes;
+ }
+ }
+
+ return SLANG_OK;
+}
+
+} // renderer_test