1#include <cstdint> 2#include <cstdio> 3#include <cstdlib> 4#include <array> 5#include <memory> 6 7#include <gtest/gtest.h> 8 9#include "GL/osmesa.h" 10#include "util/macros.h" 11#include "util/u_endian.h" 12#include "util/u_math.h" 13 14typedef struct { 15 unsigned format; 16 GLenum type; 17 int bpp; 18 uint64_t expected; 19} Params; 20 21class OSMesaRenderTestFixture : public testing::TestWithParam<Params> {}; 22 23std::string 24name_params(const testing::TestParamInfo<Params> params) { 25 auto p = params.param; 26 std::string first, second; 27 switch (p.format) { 28 case OSMESA_RGBA: 29 first = "rgba"; 30 break; 31 case OSMESA_BGRA: 32 first = "bgra"; 33 break; 34 case OSMESA_RGB: 35 first = "rgb"; 36 break; 37 case OSMESA_RGB_565: 38 first = "rgb_565"; 39 break; 40 case OSMESA_ARGB: 41 first = "argb"; 42 break; 43 } 44 45 switch (p.type) { 46 case GL_UNSIGNED_SHORT: 47 second = "unsigned_short"; 48 break; 49 case GL_UNSIGNED_BYTE: 50 second = "unsigned_byte"; 51 break; 52 case GL_FLOAT: 53 second = "float"; 54 break; 55 case GL_UNSIGNED_SHORT_5_6_5: 56 second = "unsigned_short_565"; 57 break; 58 } 59 60 return first + "_" + second; 61}; 62 63TEST_P(OSMesaRenderTestFixture, Render) 64{ 65 auto p = GetParam(); 66 const int w = 2, h = 2; 67 uint8_t pixels[w * h * 8] = { 0 }; 68 69 std::unique_ptr<osmesa_context, decltype(&OSMesaDestroyContext)> ctx{ 70 OSMesaCreateContext(p.format, NULL), &OSMesaDestroyContext}; 71 ASSERT_TRUE(ctx); 72 73 auto ret = OSMesaMakeCurrent(ctx.get(), &pixels, p.type, w, h); 74 ASSERT_EQ(ret, GL_TRUE); 75 76 glClearColor(0.25, 1.0, 0.5, 0.75); 77 78 uint64_t expected = p.expected; 79 80 /* All the formats other than 565 and RGB/byte are array formats, but our 81 * expected values are packed, so byte swap appropriately. 82 */ 83 if (UTIL_ARCH_BIG_ENDIAN) { 84 switch (p.bpp) { 85 case 8: 86 expected = util_bswap64(expected); 87 break; 88 89 case 4: 90 expected = util_bswap32(expected); 91 break; 92 93 case 3: 94 case 2: 95 break; 96 } 97 } 98 99 glClear(GL_COLOR_BUFFER_BIT); 100 glFinish(); 101 102#if 0 /* XXX */ 103 for (unsigned i = 0; i < ARRAY_SIZE(pixels); i += 4) { 104 fprintf(stderr, "pixel %d: %02x %02x %02x %02x\n", 105 i / 4, 106 pixels[i + 0], 107 pixels[i + 1], 108 pixels[i + 2], 109 pixels[i + 3]); 110 } 111#endif 112 113 for (unsigned i = 0; i < w * h; i++) { 114 switch (p.bpp) { 115 case 2: { 116 uint16_t color = 0; 117 memcpy(&color, &pixels[i * p.bpp], p.bpp); 118 ASSERT_EQ(expected, color); 119 break; 120 } 121 122 case 3: { 123 uint32_t color = ((pixels[i * p.bpp + 0] << 0) | 124 (pixels[i * p.bpp + 1] << 8) | 125 (pixels[i * p.bpp + 2] << 16)); 126 ASSERT_EQ(expected, color); 127 break; 128 } 129 130 case 4: { 131 uint32_t color = 0; 132 memcpy(&color, &pixels[i * p.bpp], p.bpp); 133 ASSERT_EQ(expected, color); 134 break; 135 } 136 137 case 8: { 138 uint64_t color = 0; 139 memcpy(&color, &pixels[i * p.bpp], p.bpp); 140 ASSERT_EQ(expected, color); 141 break; 142 } 143 144 default: 145 unreachable("bad bpp"); 146 } 147 } 148} 149 150INSTANTIATE_TEST_CASE_P( 151 OSMesaRenderTest, 152 OSMesaRenderTestFixture, 153 testing::Values( 154 Params{ OSMESA_RGBA, GL_UNSIGNED_BYTE, 4, 0xbf80ff40 }, 155 Params{ OSMESA_BGRA, GL_UNSIGNED_BYTE, 4, 0xbf40ff80 }, 156 Params{ OSMESA_ARGB, GL_UNSIGNED_BYTE, 4, 0x80ff40bf}, 157 Params{ OSMESA_RGB, GL_UNSIGNED_BYTE, 3, 0x80ff40 }, 158 Params{ OSMESA_RGBA, GL_UNSIGNED_SHORT, 8, 0xbfff8000ffff4000ull }, 159 Params{ OSMESA_RGB_565, GL_UNSIGNED_SHORT_5_6_5, 2, ((0x10 << 0) | 160 (0x3f << 5) | 161 (0x8 << 11)) } 162 ), 163 name_params 164); 165 166TEST(OSMesaRenderTest, depth) 167{ 168 std::unique_ptr<osmesa_context, decltype(&OSMesaDestroyContext)> ctx{ 169 OSMesaCreateContextExt(OSMESA_RGB_565, 24, 8, 0, NULL), &OSMesaDestroyContext}; 170 ASSERT_TRUE(ctx); 171 172 const int w = 3, h = 2; 173 uint8_t pixels[4096 * h * 2] = {0}; /* different cpp from our depth! */ 174 auto ret = OSMesaMakeCurrent(ctx.get(), &pixels, GL_UNSIGNED_SHORT_5_6_5, w, h); 175 ASSERT_EQ(ret, GL_TRUE); 176 177 /* Expand the row length for the color buffer so we can see that it doesn't affect depth. */ 178 OSMesaPixelStore(OSMESA_ROW_LENGTH, 4096); 179 180 uint32_t *depth; 181 GLint dw, dh, depth_cpp; 182 ASSERT_EQ(true, OSMesaGetDepthBuffer(ctx.get(), &dw, &dh, &depth_cpp, (void **)&depth)); 183 184 ASSERT_EQ(dw, w); 185 ASSERT_EQ(dh, h); 186 ASSERT_EQ(depth_cpp, 4); 187 188 glClearDepth(1.0); 189 glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 190 glFinish(); 191 EXPECT_EQ(depth[w * 0 + 0], 0x00ffffff); 192 EXPECT_EQ(depth[w * 0 + 1], 0x00ffffff); 193 EXPECT_EQ(depth[w * 1 + 0], 0x00ffffff); 194 EXPECT_EQ(depth[w * 1 + 1], 0x00ffffff); 195 196 /* Scissor to the top half and clear */ 197 glEnable(GL_SCISSOR_TEST); 198 glScissor(0, 1, 2, 1); 199 glClearDepth(0.0); 200 glClear(GL_DEPTH_BUFFER_BIT); 201 glFinish(); 202 EXPECT_EQ(depth[w * 0 + 0], 0x00ffffff); 203 EXPECT_EQ(depth[w * 0 + 1], 0x00ffffff); 204 EXPECT_EQ(depth[w * 1 + 0], 0x00000000); 205 EXPECT_EQ(depth[w * 1 + 1], 0x00000000); 206 207 /* Y_UP didn't affect depth buffer orientation in classic osmesa. */ 208 OSMesaPixelStore(OSMESA_Y_UP, false); 209 glScissor(0, 1, 1, 1); 210 glClearDepth(1.0); 211 glClear(GL_DEPTH_BUFFER_BIT); 212 glFinish(); 213 EXPECT_EQ(depth[w * 0 + 0], 0x00ffffff); 214 EXPECT_EQ(depth[w * 0 + 1], 0x00ffffff); 215 EXPECT_EQ(depth[w * 1 + 0], 0x00ffffff); 216 EXPECT_EQ(depth[w * 1 + 1], 0x00000000); 217} 218 219TEST(OSMesaRenderTest, depth_get_no_attachment) 220{ 221 std::unique_ptr<osmesa_context, decltype(&OSMesaDestroyContext)> ctx{ 222 OSMesaCreateContextExt(OSMESA_RGBA, 0, 0, 0, NULL), &OSMesaDestroyContext}; 223 ASSERT_TRUE(ctx); 224 225 uint32_t pixel; 226 auto ret = OSMesaMakeCurrent(ctx.get(), &pixel, GL_UNSIGNED_BYTE, 1, 1); 227 ASSERT_EQ(ret, GL_TRUE); 228 229 uint32_t *depth; 230 GLint dw = 1, dh = 1, depth_cpp = 1; 231 ASSERT_EQ(false, OSMesaGetDepthBuffer(ctx.get(), &dw, &dh, &depth_cpp, (void **)&depth)); 232 ASSERT_EQ(depth_cpp, NULL); 233 ASSERT_EQ(dw, 0); 234 ASSERT_EQ(dh, 0); 235 ASSERT_EQ(depth_cpp, 0); 236} 237 238static uint32_t be_bswap32(uint32_t x) 239{ 240 if (UTIL_ARCH_BIG_ENDIAN) 241 return util_bswap32(x); 242 else 243 return x; 244} 245 246TEST(OSMesaRenderTest, separate_buffers_per_context) 247{ 248 std::unique_ptr<osmesa_context, decltype(&OSMesaDestroyContext)> ctx1{ 249 OSMesaCreateContext(GL_RGBA, NULL), &OSMesaDestroyContext}; 250 std::unique_ptr<osmesa_context, decltype(&OSMesaDestroyContext)> ctx2{ 251 OSMesaCreateContext(GL_RGBA, NULL), &OSMesaDestroyContext}; 252 ASSERT_TRUE(ctx1); 253 ASSERT_TRUE(ctx2); 254 255 uint32_t pixel1, pixel2; 256 257 ASSERT_EQ(OSMesaMakeCurrent(ctx1.get(), &pixel1, GL_UNSIGNED_BYTE, 1, 1), GL_TRUE); 258 glClearColor(1.0, 0.0, 0.0, 0.0); 259 glClear(GL_COLOR_BUFFER_BIT); 260 glFinish(); 261 EXPECT_EQ(pixel1, be_bswap32(0x000000ff)); 262 263 ASSERT_EQ(OSMesaMakeCurrent(ctx2.get(), &pixel2, GL_UNSIGNED_BYTE, 1, 1), GL_TRUE); 264 glClearColor(0.0, 1.0, 0.0, 0.0); 265 glClear(GL_COLOR_BUFFER_BIT); 266 glFinish(); 267 EXPECT_EQ(pixel1, be_bswap32(0x000000ff)); 268 EXPECT_EQ(pixel2, be_bswap32(0x0000ff00)); 269 270 /* Leave a dangling render to pixel2 as we switch contexts (there should be 271 */ 272 glClearColor(0.0, 0.0, 1.0, 0.0); 273 glClear(GL_COLOR_BUFFER_BIT); 274 275 ASSERT_EQ(OSMesaMakeCurrent(ctx1.get(), &pixel1, GL_UNSIGNED_BYTE, 1, 1), GL_TRUE); 276 /* Draw something off screen to trigger a real flush. We should have the 277 * same contents in pixel1 as before 278 */ 279 glBegin(GL_TRIANGLES); 280 glVertex2f(-2, -2); 281 glVertex2f(-2, -2); 282 glVertex2f(-2, -2); 283 glEnd(); 284 glFinish(); 285 EXPECT_EQ(pixel1, be_bswap32(0x000000ff)); 286 EXPECT_EQ(pixel2, be_bswap32(0x00ff0000)); 287} 288 289TEST(OSMesaRenderTest, resize) 290{ 291 std::unique_ptr<osmesa_context, decltype(&OSMesaDestroyContext)> ctx{ 292 OSMesaCreateContext(GL_RGBA, NULL), &OSMesaDestroyContext}; 293 ASSERT_TRUE(ctx); 294 295 uint32_t draw1[1], draw2[4]; 296 297 ASSERT_EQ(OSMesaMakeCurrent(ctx.get(), draw1, GL_UNSIGNED_BYTE, 1, 1), GL_TRUE); 298 glClearColor(1.0, 0.0, 0.0, 0.0); 299 glClear(GL_COLOR_BUFFER_BIT); 300 glFinish(); 301 EXPECT_EQ(draw1[0], be_bswap32(0x000000ff)); 302 303 ASSERT_EQ(OSMesaMakeCurrent(ctx.get(), draw2, GL_UNSIGNED_BYTE, 2, 2), GL_TRUE); 304 glClearColor(0.0, 1.0, 0.0, 0.0); 305 glClear(GL_COLOR_BUFFER_BIT); 306 glFinish(); 307 for (unsigned i = 0; i < ARRAY_SIZE(draw2); i++) 308 EXPECT_EQ(draw2[i], be_bswap32(0x0000ff00)); 309 EXPECT_EQ(draw1[0], be_bswap32(0x000000ff)); 310} 311