17ec681f3Smrg#include <cstdint>
27ec681f3Smrg#include <cstdio>
37ec681f3Smrg#include <cstdlib>
47ec681f3Smrg#include <array>
57ec681f3Smrg#include <memory>
67ec681f3Smrg
77ec681f3Smrg#include <gtest/gtest.h>
87ec681f3Smrg
97ec681f3Smrg#include "GL/osmesa.h"
107ec681f3Smrg#include "util/macros.h"
117ec681f3Smrg#include "util/u_endian.h"
127ec681f3Smrg#include "util/u_math.h"
137ec681f3Smrg
147ec681f3Smrgtypedef struct {
157ec681f3Smrg   unsigned format;
167ec681f3Smrg   GLenum type;
177ec681f3Smrg   int bpp;
187ec681f3Smrg   uint64_t expected;
197ec681f3Smrg} Params;
207ec681f3Smrg
217ec681f3Smrgclass OSMesaRenderTestFixture : public testing::TestWithParam<Params> {};
227ec681f3Smrg
237ec681f3Smrgstd::string
247ec681f3Smrgname_params(const testing::TestParamInfo<Params> params) {
257ec681f3Smrg   auto p = params.param;
267ec681f3Smrg   std::string first, second;
277ec681f3Smrg   switch (p.format) {
287ec681f3Smrg   case OSMESA_RGBA:
297ec681f3Smrg      first = "rgba";
307ec681f3Smrg      break;
317ec681f3Smrg   case OSMESA_BGRA:
327ec681f3Smrg      first = "bgra";
337ec681f3Smrg      break;
347ec681f3Smrg   case OSMESA_RGB:
357ec681f3Smrg      first = "rgb";
367ec681f3Smrg      break;
377ec681f3Smrg   case OSMESA_RGB_565:
387ec681f3Smrg      first = "rgb_565";
397ec681f3Smrg      break;
407ec681f3Smrg   case OSMESA_ARGB:
417ec681f3Smrg      first = "argb";
427ec681f3Smrg      break;
437ec681f3Smrg   }
447ec681f3Smrg
457ec681f3Smrg   switch (p.type) {
467ec681f3Smrg   case GL_UNSIGNED_SHORT:
477ec681f3Smrg      second = "unsigned_short";
487ec681f3Smrg      break;
497ec681f3Smrg   case GL_UNSIGNED_BYTE:
507ec681f3Smrg      second = "unsigned_byte";
517ec681f3Smrg      break;
527ec681f3Smrg   case GL_FLOAT:
537ec681f3Smrg      second = "float";
547ec681f3Smrg      break;
557ec681f3Smrg   case GL_UNSIGNED_SHORT_5_6_5:
567ec681f3Smrg      second = "unsigned_short_565";
577ec681f3Smrg      break;
587ec681f3Smrg   }
597ec681f3Smrg
607ec681f3Smrg   return first + "_" + second;
617ec681f3Smrg};
627ec681f3Smrg
637ec681f3SmrgTEST_P(OSMesaRenderTestFixture, Render)
647ec681f3Smrg{
657ec681f3Smrg   auto p = GetParam();
667ec681f3Smrg   const int w = 2, h = 2;
677ec681f3Smrg   uint8_t pixels[w * h * 8] = { 0 };
687ec681f3Smrg
697ec681f3Smrg   std::unique_ptr<osmesa_context, decltype(&OSMesaDestroyContext)> ctx{
707ec681f3Smrg      OSMesaCreateContext(p.format, NULL), &OSMesaDestroyContext};
717ec681f3Smrg   ASSERT_TRUE(ctx);
727ec681f3Smrg
737ec681f3Smrg   auto ret = OSMesaMakeCurrent(ctx.get(), &pixels, p.type, w, h);
747ec681f3Smrg   ASSERT_EQ(ret, GL_TRUE);
757ec681f3Smrg
767ec681f3Smrg   glClearColor(0.25, 1.0, 0.5, 0.75);
777ec681f3Smrg
787ec681f3Smrg   uint64_t expected = p.expected;
797ec681f3Smrg
807ec681f3Smrg   /* All the formats other than 565 and RGB/byte are array formats, but our
817ec681f3Smrg    * expected values are packed, so byte swap appropriately.
827ec681f3Smrg    */
837ec681f3Smrg   if (UTIL_ARCH_BIG_ENDIAN) {
847ec681f3Smrg      switch (p.bpp) {
857ec681f3Smrg      case 8:
867ec681f3Smrg         expected = util_bswap64(expected);
877ec681f3Smrg         break;
887ec681f3Smrg
897ec681f3Smrg      case 4:
907ec681f3Smrg         expected = util_bswap32(expected);
917ec681f3Smrg         break;
927ec681f3Smrg
937ec681f3Smrg      case 3:
947ec681f3Smrg      case 2:
957ec681f3Smrg         break;
967ec681f3Smrg      }
977ec681f3Smrg   }
987ec681f3Smrg
997ec681f3Smrg   glClear(GL_COLOR_BUFFER_BIT);
1007ec681f3Smrg   glFinish();
1017ec681f3Smrg
1027ec681f3Smrg#if 0 /* XXX */
1037ec681f3Smrg   for (unsigned i = 0; i < ARRAY_SIZE(pixels); i += 4) {
1047ec681f3Smrg      fprintf(stderr, "pixel %d: %02x %02x %02x %02x\n",
1057ec681f3Smrg              i / 4,
1067ec681f3Smrg              pixels[i + 0],
1077ec681f3Smrg              pixels[i + 1],
1087ec681f3Smrg              pixels[i + 2],
1097ec681f3Smrg              pixels[i + 3]);
1107ec681f3Smrg   }
1117ec681f3Smrg#endif
1127ec681f3Smrg
1137ec681f3Smrg   for (unsigned i = 0; i < w * h; i++) {
1147ec681f3Smrg      switch (p.bpp) {
1157ec681f3Smrg      case 2: {
1167ec681f3Smrg         uint16_t color = 0;
1177ec681f3Smrg         memcpy(&color, &pixels[i * p.bpp], p.bpp);
1187ec681f3Smrg         ASSERT_EQ(expected, color);
1197ec681f3Smrg         break;
1207ec681f3Smrg      }
1217ec681f3Smrg
1227ec681f3Smrg      case 3: {
1237ec681f3Smrg         uint32_t color = ((pixels[i * p.bpp + 0] << 0) |
1247ec681f3Smrg                           (pixels[i * p.bpp + 1] << 8) |
1257ec681f3Smrg                           (pixels[i * p.bpp + 2] << 16));
1267ec681f3Smrg         ASSERT_EQ(expected, color);
1277ec681f3Smrg         break;
1287ec681f3Smrg      }
1297ec681f3Smrg
1307ec681f3Smrg      case 4: {
1317ec681f3Smrg         uint32_t color = 0;
1327ec681f3Smrg         memcpy(&color, &pixels[i * p.bpp], p.bpp);
1337ec681f3Smrg         ASSERT_EQ(expected, color);
1347ec681f3Smrg         break;
1357ec681f3Smrg      }
1367ec681f3Smrg
1377ec681f3Smrg      case 8: {
1387ec681f3Smrg         uint64_t color = 0;
1397ec681f3Smrg         memcpy(&color, &pixels[i * p.bpp], p.bpp);
1407ec681f3Smrg         ASSERT_EQ(expected, color);
1417ec681f3Smrg         break;
1427ec681f3Smrg      }
1437ec681f3Smrg
1447ec681f3Smrg      default:
1457ec681f3Smrg         unreachable("bad bpp");
1467ec681f3Smrg      }
1477ec681f3Smrg   }
1487ec681f3Smrg}
1497ec681f3Smrg
1507ec681f3SmrgINSTANTIATE_TEST_CASE_P(
1517ec681f3Smrg   OSMesaRenderTest,
1527ec681f3Smrg   OSMesaRenderTestFixture,
1537ec681f3Smrg   testing::Values(
1547ec681f3Smrg      Params{ OSMESA_RGBA, GL_UNSIGNED_BYTE,  4, 0xbf80ff40 },
1557ec681f3Smrg      Params{ OSMESA_BGRA, GL_UNSIGNED_BYTE,  4, 0xbf40ff80 },
1567ec681f3Smrg      Params{ OSMESA_ARGB, GL_UNSIGNED_BYTE,  4, 0x80ff40bf},
1577ec681f3Smrg      Params{ OSMESA_RGB,  GL_UNSIGNED_BYTE,  3, 0x80ff40 },
1587ec681f3Smrg      Params{ OSMESA_RGBA, GL_UNSIGNED_SHORT, 8, 0xbfff8000ffff4000ull },
1597ec681f3Smrg      Params{ OSMESA_RGB_565, GL_UNSIGNED_SHORT_5_6_5, 2, ((0x10 << 0) |
1607ec681f3Smrg                                                           (0x3f << 5) |
1617ec681f3Smrg                                                           (0x8 << 11)) }
1627ec681f3Smrg   ),
1637ec681f3Smrg   name_params
1647ec681f3Smrg);
1657ec681f3Smrg
1667ec681f3SmrgTEST(OSMesaRenderTest, depth)
1677ec681f3Smrg{
1687ec681f3Smrg   std::unique_ptr<osmesa_context, decltype(&OSMesaDestroyContext)> ctx{
1697ec681f3Smrg      OSMesaCreateContextExt(OSMESA_RGB_565, 24, 8, 0, NULL), &OSMesaDestroyContext};
1707ec681f3Smrg   ASSERT_TRUE(ctx);
1717ec681f3Smrg
1727ec681f3Smrg   const int w = 3, h = 2;
1737ec681f3Smrg   uint8_t pixels[4096 * h * 2] = {0}; /* different cpp from our depth! */
1747ec681f3Smrg   auto ret = OSMesaMakeCurrent(ctx.get(), &pixels, GL_UNSIGNED_SHORT_5_6_5, w, h);
1757ec681f3Smrg   ASSERT_EQ(ret, GL_TRUE);
1767ec681f3Smrg
1777ec681f3Smrg   /* Expand the row length for the color buffer so we can see that it doesn't affect depth. */
1787ec681f3Smrg   OSMesaPixelStore(OSMESA_ROW_LENGTH, 4096);
1797ec681f3Smrg
1807ec681f3Smrg   uint32_t *depth;
1817ec681f3Smrg   GLint dw, dh, depth_cpp;
1827ec681f3Smrg   ASSERT_EQ(true, OSMesaGetDepthBuffer(ctx.get(), &dw, &dh, &depth_cpp, (void **)&depth));
1837ec681f3Smrg
1847ec681f3Smrg   ASSERT_EQ(dw, w);
1857ec681f3Smrg   ASSERT_EQ(dh, h);
1867ec681f3Smrg   ASSERT_EQ(depth_cpp, 4);
1877ec681f3Smrg
1887ec681f3Smrg   glClearDepth(1.0);
1897ec681f3Smrg   glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1907ec681f3Smrg   glFinish();
1917ec681f3Smrg   EXPECT_EQ(depth[w * 0 + 0], 0x00ffffff);
1927ec681f3Smrg   EXPECT_EQ(depth[w * 0 + 1], 0x00ffffff);
1937ec681f3Smrg   EXPECT_EQ(depth[w * 1 + 0], 0x00ffffff);
1947ec681f3Smrg   EXPECT_EQ(depth[w * 1 + 1], 0x00ffffff);
1957ec681f3Smrg
1967ec681f3Smrg   /* Scissor to the top half and clear */
1977ec681f3Smrg   glEnable(GL_SCISSOR_TEST);
1987ec681f3Smrg   glScissor(0, 1, 2, 1);
1997ec681f3Smrg   glClearDepth(0.0);
2007ec681f3Smrg   glClear(GL_DEPTH_BUFFER_BIT);
2017ec681f3Smrg   glFinish();
2027ec681f3Smrg   EXPECT_EQ(depth[w * 0 + 0], 0x00ffffff);
2037ec681f3Smrg   EXPECT_EQ(depth[w * 0 + 1], 0x00ffffff);
2047ec681f3Smrg   EXPECT_EQ(depth[w * 1 + 0], 0x00000000);
2057ec681f3Smrg   EXPECT_EQ(depth[w * 1 + 1], 0x00000000);
2067ec681f3Smrg
2077ec681f3Smrg   /* Y_UP didn't affect depth buffer orientation in classic osmesa. */
2087ec681f3Smrg   OSMesaPixelStore(OSMESA_Y_UP, false);
2097ec681f3Smrg   glScissor(0, 1, 1, 1);
2107ec681f3Smrg   glClearDepth(1.0);
2117ec681f3Smrg   glClear(GL_DEPTH_BUFFER_BIT);
2127ec681f3Smrg   glFinish();
2137ec681f3Smrg   EXPECT_EQ(depth[w * 0 + 0], 0x00ffffff);
2147ec681f3Smrg   EXPECT_EQ(depth[w * 0 + 1], 0x00ffffff);
2157ec681f3Smrg   EXPECT_EQ(depth[w * 1 + 0], 0x00ffffff);
2167ec681f3Smrg   EXPECT_EQ(depth[w * 1 + 1], 0x00000000);
2177ec681f3Smrg}
2187ec681f3Smrg
2197ec681f3SmrgTEST(OSMesaRenderTest, depth_get_no_attachment)
2207ec681f3Smrg{
2217ec681f3Smrg   std::unique_ptr<osmesa_context, decltype(&OSMesaDestroyContext)> ctx{
2227ec681f3Smrg      OSMesaCreateContextExt(OSMESA_RGBA, 0, 0, 0, NULL), &OSMesaDestroyContext};
2237ec681f3Smrg   ASSERT_TRUE(ctx);
2247ec681f3Smrg
2257ec681f3Smrg   uint32_t pixel;
2267ec681f3Smrg   auto ret = OSMesaMakeCurrent(ctx.get(), &pixel, GL_UNSIGNED_BYTE, 1, 1);
2277ec681f3Smrg   ASSERT_EQ(ret, GL_TRUE);
2287ec681f3Smrg
2297ec681f3Smrg   uint32_t *depth;
2307ec681f3Smrg   GLint dw = 1, dh = 1, depth_cpp = 1;
2317ec681f3Smrg   ASSERT_EQ(false, OSMesaGetDepthBuffer(ctx.get(), &dw, &dh, &depth_cpp, (void **)&depth));
2327ec681f3Smrg   ASSERT_EQ(depth_cpp, NULL);
2337ec681f3Smrg   ASSERT_EQ(dw, 0);
2347ec681f3Smrg   ASSERT_EQ(dh, 0);
2357ec681f3Smrg   ASSERT_EQ(depth_cpp, 0);
2367ec681f3Smrg}
2377ec681f3Smrg
2387ec681f3Smrgstatic uint32_t be_bswap32(uint32_t x)
2397ec681f3Smrg{
2407ec681f3Smrg   if (UTIL_ARCH_BIG_ENDIAN)
2417ec681f3Smrg      return util_bswap32(x);
2427ec681f3Smrg   else
2437ec681f3Smrg      return x;
2447ec681f3Smrg}
2457ec681f3Smrg
2467ec681f3SmrgTEST(OSMesaRenderTest, separate_buffers_per_context)
2477ec681f3Smrg{
2487ec681f3Smrg   std::unique_ptr<osmesa_context, decltype(&OSMesaDestroyContext)> ctx1{
2497ec681f3Smrg      OSMesaCreateContext(GL_RGBA, NULL), &OSMesaDestroyContext};
2507ec681f3Smrg   std::unique_ptr<osmesa_context, decltype(&OSMesaDestroyContext)> ctx2{
2517ec681f3Smrg      OSMesaCreateContext(GL_RGBA, NULL), &OSMesaDestroyContext};
2527ec681f3Smrg   ASSERT_TRUE(ctx1);
2537ec681f3Smrg   ASSERT_TRUE(ctx2);
2547ec681f3Smrg
2557ec681f3Smrg   uint32_t pixel1, pixel2;
2567ec681f3Smrg
2577ec681f3Smrg   ASSERT_EQ(OSMesaMakeCurrent(ctx1.get(), &pixel1, GL_UNSIGNED_BYTE, 1, 1), GL_TRUE);
2587ec681f3Smrg   glClearColor(1.0, 0.0, 0.0, 0.0);
2597ec681f3Smrg   glClear(GL_COLOR_BUFFER_BIT);
2607ec681f3Smrg   glFinish();
2617ec681f3Smrg   EXPECT_EQ(pixel1, be_bswap32(0x000000ff));
2627ec681f3Smrg
2637ec681f3Smrg   ASSERT_EQ(OSMesaMakeCurrent(ctx2.get(), &pixel2, GL_UNSIGNED_BYTE, 1, 1), GL_TRUE);
2647ec681f3Smrg   glClearColor(0.0, 1.0, 0.0, 0.0);
2657ec681f3Smrg   glClear(GL_COLOR_BUFFER_BIT);
2667ec681f3Smrg   glFinish();
2677ec681f3Smrg   EXPECT_EQ(pixel1, be_bswap32(0x000000ff));
2687ec681f3Smrg   EXPECT_EQ(pixel2, be_bswap32(0x0000ff00));
2697ec681f3Smrg
2707ec681f3Smrg   /* Leave a dangling render to pixel2 as we switch contexts (there should be
2717ec681f3Smrg    */
2727ec681f3Smrg   glClearColor(0.0, 0.0, 1.0, 0.0);
2737ec681f3Smrg   glClear(GL_COLOR_BUFFER_BIT);
2747ec681f3Smrg
2757ec681f3Smrg   ASSERT_EQ(OSMesaMakeCurrent(ctx1.get(), &pixel1, GL_UNSIGNED_BYTE, 1, 1), GL_TRUE);
2767ec681f3Smrg   /* Draw something off screen to trigger a real flush.  We should have the
2777ec681f3Smrg    * same contents in pixel1 as before
2787ec681f3Smrg    */
2797ec681f3Smrg   glBegin(GL_TRIANGLES);
2807ec681f3Smrg   glVertex2f(-2, -2);
2817ec681f3Smrg   glVertex2f(-2, -2);
2827ec681f3Smrg   glVertex2f(-2, -2);
2837ec681f3Smrg   glEnd();
2847ec681f3Smrg   glFinish();
2857ec681f3Smrg   EXPECT_EQ(pixel1, be_bswap32(0x000000ff));
2867ec681f3Smrg   EXPECT_EQ(pixel2, be_bswap32(0x00ff0000));
2877ec681f3Smrg}
2887ec681f3Smrg
2897ec681f3SmrgTEST(OSMesaRenderTest, resize)
2907ec681f3Smrg{
2917ec681f3Smrg   std::unique_ptr<osmesa_context, decltype(&OSMesaDestroyContext)> ctx{
2927ec681f3Smrg      OSMesaCreateContext(GL_RGBA, NULL), &OSMesaDestroyContext};
2937ec681f3Smrg   ASSERT_TRUE(ctx);
2947ec681f3Smrg
2957ec681f3Smrg   uint32_t draw1[1], draw2[4];
2967ec681f3Smrg
2977ec681f3Smrg   ASSERT_EQ(OSMesaMakeCurrent(ctx.get(), draw1, GL_UNSIGNED_BYTE, 1, 1), GL_TRUE);
2987ec681f3Smrg   glClearColor(1.0, 0.0, 0.0, 0.0);
2997ec681f3Smrg   glClear(GL_COLOR_BUFFER_BIT);
3007ec681f3Smrg   glFinish();
3017ec681f3Smrg   EXPECT_EQ(draw1[0], be_bswap32(0x000000ff));
3027ec681f3Smrg
3037ec681f3Smrg   ASSERT_EQ(OSMesaMakeCurrent(ctx.get(), draw2, GL_UNSIGNED_BYTE, 2, 2), GL_TRUE);
3047ec681f3Smrg   glClearColor(0.0, 1.0, 0.0, 0.0);
3057ec681f3Smrg   glClear(GL_COLOR_BUFFER_BIT);
3067ec681f3Smrg   glFinish();
3077ec681f3Smrg   for (unsigned i = 0; i < ARRAY_SIZE(draw2); i++)
3087ec681f3Smrg      EXPECT_EQ(draw2[i], be_bswap32(0x0000ff00));
3097ec681f3Smrg   EXPECT_EQ(draw1[0], be_bswap32(0x000000ff));
3107ec681f3Smrg}
311