summaryrefslogtreecommitdiffstats
path: root/tools/render-test/surface.cpp
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2018-05-03 18:42:13 -0400
committerTim Foley <tfoleyNV@users.noreply.github.com>2018-05-03 15:42:13 -0700
commitf8472940229e8582ec9f941069fc9576bd09b94c (patch)
tree9b387a65abc42094e7a1e0687b793cb0fc5c5eaa /tools/render-test/surface.cpp
parentc216f00f1eaff368229cb8430422972fcac801b7 (diff)
Added Surface type - as a simple value type to hold a 2d collection of pixels. (#548)
Added PngSerializeUtil allows currently for just writing Surface of RGBA format. Removes dependency on stbi_image except for in PngSerializeUtil. Removed use of gWindowWidth/Height globals - pass the height into initialize or Renderer.
Diffstat (limited to 'tools/render-test/surface.cpp')
-rw-r--r--tools/render-test/surface.cpp191
1 files changed, 191 insertions, 0 deletions
diff --git a/tools/render-test/surface.cpp b/tools/render-test/surface.cpp
new file mode 100644
index 000000000..3f96052ce
--- /dev/null
+++ b/tools/render-test/surface.cpp
@@ -0,0 +1,191 @@
+// surface.cpp
+#include "surface.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "../../source/core/list.h"
+
+namespace renderer_test {
+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_MEM_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 = RendererUtil::getFormatSize(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.SetSize(rowSizeInBytes);
+ uint8_t* buffer = bufferList.Buffer();
+
+ 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);
+ }
+}
+
+} // renderer_test