tests: add basic blit (copy, clear, and resolve) tests
authorChia-I Wu <olv@lunarg.com>
Tue, 21 Oct 2014 03:06:26 +0000 (11:06 +0800)
committerCourtney Goeltzenleuchter <courtney@LunarG.com>
Fri, 31 Oct 2014 21:29:18 +0000 (15:29 -0600)
tests/CMakeLists.txt
tests/blit_tests.cpp [new file with mode: 0644]

index 2b156ea..58d0662 100644 (file)
@@ -75,6 +75,12 @@ set_target_properties(xgl_compiler_render_tests
    COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1")
 target_link_libraries(xgl_compiler_render_tests XGL gtest gtest_main ${TEST_LIBRARIES})
 
+add_executable(xgl_blit_tests blit_tests.cpp ${COMMON_CPP} displayengine.cpp)
+set_target_properties(xgl_blit_tests
+   PROPERTIES
+   COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1")
+target_link_libraries(xgl_blit_tests XGL gtest gtest_main ${TEST_LIBRARIES})
+
 add_executable(xgl_base_render_test base_render_test.cpp ${COMMON_CPP} displayengine.cpp)
 set_target_properties(xgl_base_render_test
    PROPERTIES
diff --git a/tests/blit_tests.cpp b/tests/blit_tests.cpp
new file mode 100644 (file)
index 0000000..7a59c8e
--- /dev/null
@@ -0,0 +1,561 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+//  XGL tests
+//
+//  Copyright (C) 2014 LunarG, Inc.
+//
+//  Permission is hereby granted, free of charge, to any person obtaining a
+//  copy of this software and associated documentation files (the "Software"),
+//  to deal in the Software without restriction, including without limitation
+//  the rights to use, copy, modify, merge, publish, distribute, sublicense,
+//  and/or sell copies of the Software, and to permit persons to whom the
+//  Software is furnished to do so, subject to the following conditions:
+//
+//  The above copyright notice and this permission notice shall be included
+//  in all copies or substantial portions of the Software.
+//
+//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+//  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+//  DEALINGS IN THE SOFTWARE.
+
+// Blit (copy, clear, and resolve) tests
+
+#include <string.h>
+#include <xgl.h>
+#include "gtest-1.7.0/include/gtest/gtest.h"
+#include "xgldevice.h"
+#include "xglimage.h"
+#include "xgltestframework.h"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+class XglBlitTest : public XglTestFramework
+{
+protected:
+    XGL_APPLICATION_INFO app_info;
+    XglDevice *m_device;
+
+    XGL_CMD_BUFFER m_cmd;
+
+    XGL_MEMORY_REF m_mem_refs[8];
+    XGL_UINT m_mem_ref_count;
+
+    virtual void SetUp();
+    virtual void TearDown();
+
+    XGL_DEVICE device() { return m_device->device(); }
+
+    void ClearMemoryRefs()
+    {
+        m_mem_ref_count = 0;
+    }
+
+    void AddMemoryRef(XGL_GPU_MEMORY mem, bool readonly)
+    {
+        ASSERT_LE(m_mem_ref_count, ARRAY_SIZE(m_mem_refs));
+
+        m_mem_refs[m_mem_ref_count].mem = mem;
+        m_mem_refs[m_mem_ref_count].flags =
+            (readonly) ? XGL_MEMORY_REF_READ_ONLY_BIT : 0;
+        m_mem_ref_count++;
+    }
+
+    XGL_GPU_MEMORY AllocMemory(XGL_GPU_SIZE size)
+    {
+        XGL_MEMORY_ALLOC_INFO info;
+        XGL_GPU_MEMORY mem;
+        XGL_RESULT err;
+
+        memset(&info, 0, sizeof(info));
+        info.sType = XGL_STRUCTURE_TYPE_MEMORY_ALLOC_INFO;
+        info.allocationSize = size;
+        info.alignment = 1;
+        info.heapCount = 1;
+        info.memPriority = XGL_MEMORY_PRIORITY_NORMAL;
+
+        err = xglAllocMemory(device(), &info, &mem);
+        if (err)
+            mem = XGL_NULL_HANDLE;
+
+        return mem;
+    }
+
+    XGL_GPU_MEMORY AddMemory(XGL_GPU_SIZE size, bool readonly)
+    {
+        XGL_GPU_MEMORY mem;
+
+        mem = AllocMemory(size);
+        if (mem)
+            AddMemoryRef(mem, readonly);
+
+        return mem;
+    }
+
+    void BeginCmd()
+    {
+        XGL_RESULT err;
+
+        err = xglBeginCommandBuffer(m_cmd,
+                XGL_CMD_BUFFER_OPTIMIZE_GPU_SMALL_BATCH_BIT |
+                XGL_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT);
+        ASSERT_XGL_SUCCESS(err);
+    }
+
+    void EndAndSubmitCmd()
+    {
+        XGL_RESULT err;
+
+        err = xglEndCommandBuffer(m_cmd);
+        ASSERT_XGL_SUCCESS(err);
+
+        err = xglQueueSubmit(m_device->m_queue, 1, &m_cmd, m_mem_ref_count, m_mem_refs, NULL );
+        ASSERT_XGL_SUCCESS(err);
+
+        err = xglQueueWaitIdle(m_device->m_queue);
+        ASSERT_XGL_SUCCESS(err);
+    }
+};
+
+void XglBlitTest::SetUp()
+{
+    XGL_CMD_BUFFER_CREATE_INFO cmd_info;
+    XGL_PHYSICAL_GPU gpu;
+    XGL_UINT count;
+    XGL_RESULT err;
+
+    memset(&app_info, 0, sizeof(app_info));
+    app_info.sType = XGL_STRUCTURE_TYPE_APPLICATION_INFO;
+    app_info.pNext = NULL;
+    app_info.pAppName = (const XGL_CHAR *) "blit tests";
+    app_info.appVersion = 1;
+    app_info.pEngineName = (const XGL_CHAR *) "unittest";
+    app_info.engineVersion = 1;
+    app_info.apiVersion = XGL_MAKE_VERSION(0, 22, 0);
+
+    err = xglInitAndEnumerateGpus(&app_info, NULL, 1, &count, &gpu);
+    ASSERT_XGL_SUCCESS(err);
+    ASSERT_GE(1, count) << "No GPU available";
+
+    m_device = new XglDevice(0, gpu);
+    m_device->get_device_queue();
+
+    memset(&cmd_info, 0, sizeof(cmd_info));
+    cmd_info.sType = XGL_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO;
+    cmd_info.queueType = XGL_QUEUE_TYPE_GRAPHICS;
+
+    err = xglCreateCommandBuffer(device(), &cmd_info, &m_cmd);
+    ASSERT_XGL_SUCCESS(err) << "xglCreateCommandBuffer failed";
+}
+
+void XglBlitTest::TearDown()
+{
+    XGL_UINT dummy_count;
+
+    xglDestroyObject(m_cmd);
+    xglInitAndEnumerateGpus(&app_info, NULL, 0, &dummy_count, NULL);
+}
+
+TEST_F(XglBlitTest, FillMemory)
+{
+    const struct {
+        XGL_GPU_SIZE offset;
+        XGL_GPU_SIZE size;
+        XGL_UINT value;
+    } ranges[] = {
+        {  0, 64, 0x11111111 }, // 16-byte aligned
+        { 64, 12, 0x22222222 }, // 4-byte aligned
+        { 76,  4, 0x33333333 }, // min. fill size
+        { 80, 20, 0x44444444 },
+        { 92,  8, 0x55555555 }, // overlapped
+    };
+    XGL_GPU_MEMORY mem;
+    XGL_RESULT err;
+    void *data;
+    XGL_UINT i;
+
+    ClearMemoryRefs();
+
+    mem = AddMemory(256, false);
+    ASSERT_NE((XGL_GPU_MEMORY) XGL_NULL_HANDLE, mem);
+
+    BeginCmd();
+    for (i = 0; i < ARRAY_SIZE(ranges); i++) {
+        xglCmdFillMemory(m_cmd, mem, ranges[i].offset,
+                ranges[i].size, ranges[i].value);
+    }
+    EndAndSubmitCmd();
+
+    err = xglMapMemory(mem, 0, &data);
+    ASSERT_XGL_SUCCESS(err);
+
+    for (i = 0; i < ARRAY_SIZE(ranges); i++) {
+        const XGL_UINT expected = ranges[i].value;
+        const XGL_UINT *real = (const XGL_UINT *)
+            ((char *) data + ranges[i].offset);
+        XGL_UINT count, j;
+
+        count = ranges[i].size / 4;
+
+        /* check if the next range overlaps */
+        if (i + 1 < ARRAY_SIZE(ranges)) {
+            if (ranges[i].offset + ranges[i].size > ranges[i + 1].offset)
+                count = (ranges[i + 1].offset - ranges[i].offset) / 4;
+        }
+
+        for (j = 0; j < count; j++)
+            ASSERT_EQ(expected, real[j]);
+    }
+
+    xglUnmapMemory(mem);
+    xglFreeMemory(mem);
+}
+
+TEST_F(XglBlitTest, CopyMemory)
+{
+    XGL_GPU_MEMORY src, dst;
+    XGL_MEMORY_COPY regions[17];
+    XGL_RESULT err;
+    void *data;
+    XGL_UINT i;
+
+    ClearMemoryRefs();
+
+    src = AddMemory(256, false);
+    ASSERT_NE((XGL_GPU_MEMORY) XGL_NULL_HANDLE, src);
+
+    err = xglMapMemory(src, 0, &data);
+    ASSERT_XGL_SUCCESS(err);
+    for (i = 0; i < 256; i++)
+        ((char *) data)[i] = i;
+    xglUnmapMemory(src);
+
+    dst = AddMemory(256, false);
+    ASSERT_NE((XGL_GPU_MEMORY) XGL_NULL_HANDLE, dst);
+
+    /* copy with various alignments */
+    for (i = 0; i < 16; i++) {
+        regions[i].copySize = i + 1;
+        regions[i].srcOffset = i * 8;
+
+        if (i > 0) {
+            regions[i].destOffset = regions[i - 1].destOffset +
+                                    regions[i - 1].copySize;
+        } else {
+            regions[i].destOffset = 0;
+        }
+    }
+
+    regions[i].srcOffset = 192;
+    regions[i].destOffset = 192;
+    regions[i].copySize = 64;
+
+    BeginCmd();
+
+    xglCmdCopyMemory(m_cmd, src, dst, 16, regions);
+    xglCmdCopyMemory(m_cmd, src, dst, 1, &regions[16]);
+
+    EndAndSubmitCmd();
+
+    err = xglMapMemory(dst, 0, &data);
+    ASSERT_XGL_SUCCESS(err);
+
+    for (i = 0; i < ARRAY_SIZE(regions); i++) {
+        const unsigned char *real = (const unsigned char *) data +
+            regions[i].destOffset;
+        XGL_UINT j;
+
+        for (j = 0; j < regions[i].copySize; j++)
+            ASSERT_EQ(regions[i].srcOffset + j, real[j]);
+    }
+
+    xglUnmapMemory(dst);
+    xglFreeMemory(src);
+    xglFreeMemory(dst);
+}
+
+TEST_F(XglBlitTest, ClearColorImageBasic)
+{
+    const XGL_FLOAT color[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
+    const XGL_UINT width = 64;
+    const XGL_UINT height = 64;
+    XglImage *img;
+    XGL_FORMAT format;
+    XGL_IMAGE_SUBRESOURCE subres;
+    XGL_IMAGE_SUBRESOURCE_RANGE subres_range;
+    XGL_IMAGE_STATE_TRANSITION transition;
+    XGL_RESULT err;
+
+    format.channelFormat = XGL_CH_FMT_R8G8B8A8;
+    format.numericFormat = XGL_NUM_FMT_UNORM;
+
+    subres.aspect = XGL_IMAGE_ASPECT_COLOR;
+    subres.mipLevel = 0;
+    subres.arraySlice = 0;
+
+    subres_range.aspect = XGL_IMAGE_ASPECT_COLOR;
+    subres_range.baseMipLevel = 0;
+    subres_range.mipLevels = 1;
+    subres_range.baseArraySlice = 0;
+    subres_range.arraySize = 1;
+
+    img = new XglImage(m_device);
+    img->init(width, height, format, XGL_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
+
+    ClearMemoryRefs();
+    AddMemoryRef(img->memory(), false);
+
+    BeginCmd();
+
+    transition.image = img->image();
+    transition.oldState = XGL_IMAGE_STATE_UNINITIALIZED_TARGET;
+    transition.newState = XGL_IMAGE_STATE_CLEAR;
+    transition.subresourceRange = subres_range;
+    xglCmdPrepareImages(m_cmd, 1, &transition);
+
+    xglCmdClearColorImage(m_cmd, img->image(), color, 1, &subres_range);
+
+    EndAndSubmitCmd();
+
+    {
+        XGL_SUBRESOURCE_LAYOUT layout;
+        XGL_SIZE layout_size;
+        XGL_UINT x, y;
+        void *data;
+
+        err = img->MapMemory(&data);
+        ASSERT_XGL_SUCCESS(err);
+
+        err = xglGetImageSubresourceInfo(img->image(), &subres,
+                XGL_INFO_TYPE_SUBRESOURCE_LAYOUT, &layout_size, &layout);
+        ASSERT_XGL_SUCCESS(err);
+        ASSERT_EQ(sizeof(layout), layout_size);
+
+        for (y = 0; y < height; y++) {
+            const XGL_UINT *real = (const XGL_UINT *)
+                ((char *) data + layout.offset + layout.rowPitch * y);
+
+            for (x = 0; x < width; x++)
+                ASSERT_EQ(0xff00ff00, real[x]);
+        }
+
+        img->UnmapMemory();
+    }
+
+    delete img;
+}
+
+TEST_F(XglBlitTest, CopyImageBasic)
+{
+    const XGL_FLOAT color[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
+    const XGL_UINT width = 64;
+    const XGL_UINT height = 64;
+    XglImage *src, *dst;
+    XGL_FORMAT format;
+    XGL_IMAGE_SUBRESOURCE subres;
+    XGL_IMAGE_SUBRESOURCE_RANGE subres_range;
+    XGL_IMAGE_STATE_TRANSITION transition;
+    XGL_RESULT err;
+
+    format.channelFormat = XGL_CH_FMT_R8G8B8A8;
+    format.numericFormat = XGL_NUM_FMT_UNORM;
+
+    subres.aspect = XGL_IMAGE_ASPECT_COLOR;
+    subres.mipLevel = 0;
+    subres.arraySlice = 0;
+
+    subres_range.aspect = XGL_IMAGE_ASPECT_COLOR;
+    subres_range.baseMipLevel = 0;
+    subres_range.mipLevels = 1;
+    subres_range.baseArraySlice = 0;
+    subres_range.arraySize = 1;
+
+    src = new XglImage(m_device);
+    src->init(width, height, format, XGL_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
+    dst = new XglImage(m_device);
+    dst->init(width, height, format, XGL_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
+
+    ClearMemoryRefs();
+    AddMemoryRef(src->memory(), false);
+    AddMemoryRef(dst->memory(), false);
+
+    BeginCmd();
+
+    transition.image = src->image();
+    transition.oldState = XGL_IMAGE_STATE_UNINITIALIZED_TARGET;
+    transition.newState = XGL_IMAGE_STATE_CLEAR;
+    transition.subresourceRange = subres_range;
+    xglCmdPrepareImages(m_cmd, 1, &transition);
+
+    xglCmdClearColorImage(m_cmd, src->image(), color, 1, &subres_range);
+
+    transition.oldState = XGL_IMAGE_STATE_CLEAR;
+    transition.newState = XGL_IMAGE_STATE_DATA_TRANSFER;
+    xglCmdPrepareImages(m_cmd, 1, &transition);
+
+    transition.image = dst->image();
+    transition.oldState = XGL_IMAGE_STATE_UNINITIALIZED_TARGET;
+    transition.newState = XGL_IMAGE_STATE_DATA_TRANSFER;
+    xglCmdPrepareImages(m_cmd, 1, &transition);
+
+    XGL_IMAGE_COPY copy;
+    memset(&copy, 0, sizeof(copy));
+    copy.srcSubresource = subres;
+    copy.destSubresource = subres;
+    copy.extent.width = width;
+    copy.extent.height = height;
+    copy.extent.depth = 1;
+    xglCmdCopyImage(m_cmd, src->image(), dst->image(), 1, &copy);
+
+    EndAndSubmitCmd();
+
+    {
+        XGL_SUBRESOURCE_LAYOUT layout;
+        XGL_SIZE layout_size;
+        void *data;
+        XGL_UINT x, y;
+
+        err = dst->MapMemory(&data);
+        ASSERT_XGL_SUCCESS(err);
+
+        err = xglGetImageSubresourceInfo(dst->image(), &subres,
+                XGL_INFO_TYPE_SUBRESOURCE_LAYOUT, &layout_size, &layout);
+        ASSERT_XGL_SUCCESS(err);
+        ASSERT_EQ(sizeof(layout), layout_size);
+
+        for (y = 0; y < height; y++) {
+            const XGL_UINT *real = (const XGL_UINT *)
+                ((char *) data + layout.offset + layout.rowPitch * y);
+
+            for (x = 0; x < width; x++)
+                ASSERT_EQ(0xff00ff00, real[x]);
+        }
+
+        dst->UnmapMemory();
+    }
+
+    delete src;
+    delete dst;
+}
+
+TEST_F(XglBlitTest, ClearDepthStencilBasic)
+{
+    const XGL_FLOAT clear_depth = 0.4f;
+    const XGL_UINT width = 64;
+    const XGL_UINT height = 64;
+    XglImage *img;
+    XGL_FORMAT format;
+    XGL_IMAGE_SUBRESOURCE subres;
+    XGL_IMAGE_SUBRESOURCE_RANGE subres_range;
+    XGL_IMAGE_STATE_TRANSITION transition;
+    XGL_RESULT err;
+
+    format.channelFormat = XGL_CH_FMT_R32;
+    format.numericFormat = XGL_NUM_FMT_DS;
+
+    subres.aspect = XGL_IMAGE_ASPECT_DEPTH;
+    subres.mipLevel = 0;
+    subres.arraySlice = 0;
+
+    subres_range.aspect = XGL_IMAGE_ASPECT_DEPTH;
+    subres_range.baseMipLevel = 0;
+    subres_range.mipLevels = 1;
+    subres_range.baseArraySlice = 0;
+    subres_range.arraySize = 1;
+
+    img = new XglImage(m_device);
+    img->init(width, height, format, XGL_IMAGE_USAGE_DEPTH_STENCIL_BIT,
+              XGL_OPTIMAL_TILING);
+
+    ClearMemoryRefs();
+    AddMemoryRef(img->memory(), false);
+
+    BeginCmd();
+
+    transition.image = img->image();
+    transition.oldState = XGL_IMAGE_STATE_UNINITIALIZED_TARGET;
+    transition.newState = XGL_IMAGE_STATE_CLEAR;
+    transition.subresourceRange = subres_range;
+    xglCmdPrepareImages(m_cmd, 1, &transition);
+
+    xglCmdClearDepthStencil(m_cmd, img->image(), clear_depth,
+            0, 1, &subres_range);
+
+    EndAndSubmitCmd();
+
+    /*
+     * TODO xglCmdCopyImageToMemory to linearize
+     *
+     * This works only because xglMapMemory calls intel_bo_map_gtt_async.
+     */
+    {
+        XGL_SUBRESOURCE_LAYOUT layout;
+        XGL_SIZE layout_size;
+        XGL_UINT x, y;
+        void *data;
+
+        err = img->MapMemory(&data);
+        ASSERT_XGL_SUCCESS(err);
+
+        err = xglGetImageSubresourceInfo(img->image(), &subres,
+                XGL_INFO_TYPE_SUBRESOURCE_LAYOUT, &layout_size, &layout);
+        ASSERT_XGL_SUCCESS(err);
+        ASSERT_EQ(sizeof(layout), layout_size);
+
+        for (y = 0; y < height; y++) {
+            const float *real = (const float *)
+                ((char *) data + layout.offset + layout.rowPitch * y);
+
+            for (x = 0; x < width; x++)
+                ASSERT_EQ(clear_depth, real[x]);
+        }
+
+        img->UnmapMemory();
+    }
+}
+
+int main(int argc, char **argv)
+{
+    int result;
+
+    ::testing::InitGoogleTest(&argc, argv);
+    XglTestFramework::InitArgs(&argc, argv);
+
+    ::testing::Environment* const xgl_test_env = ::testing::AddGlobalTestEnvironment(new TestEnvironment);
+
+    result = RUN_ALL_TESTS();
+
+    XglTestFramework::Finish();
+    return result;
+}