1 /*
2 -----------------------------------------------------------------------------
3 This source file is part of OGRE
4     (Object-oriented Graphics Rendering Engine)
5 For the latest info, see http://www.ogre3d.org/
6 
7 Copyright (c) 2000-2013 Torus Knot Software Ltd
8 
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15 
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 THE SOFTWARE.
26 -----------------------------------------------------------------------------
27 */
28 #include "PixelFormatTests.h"
29 #include <cstdlib>
30 
31 // Register the suite
32 CPPUNIT_TEST_SUITE_REGISTRATION( PixelFormatTests );
33 
setUp()34 void PixelFormatTests::setUp()
35 {
36     size = 4096;
37     randomData = new uint8[size];
38     temp = new uint8[size];
39     temp2 = new uint8[size];
40     // Generate reproducible random data
41     srand(0);
42     for(unsigned int x=0; x<(unsigned int)size; x++)
43         randomData[x] = (uint8)rand();
44 }
45 
tearDown()46 void PixelFormatTests::tearDown()
47 {
48     delete [] randomData;
49     delete [] temp;
50     delete [] temp2;
51 }
52 
53 
testIntegerPackUnpack()54 void PixelFormatTests::testIntegerPackUnpack()
55 {
56 
57 }
58 
testFloatPackUnpack()59 void PixelFormatTests::testFloatPackUnpack()
60 {
61     // Float32
62     float data[4] = {1.0f, 2.0f, 3.0f, 4.0f};
63     float r,g,b,a;
64     PixelUtil::unpackColour(&r, &g, &b, &a, PF_FLOAT32_RGBA, data);
65     CPPUNIT_ASSERT_EQUAL(r, 1.0f);
66     CPPUNIT_ASSERT_EQUAL(g, 2.0f);
67     CPPUNIT_ASSERT_EQUAL(b, 3.0f);
68     CPPUNIT_ASSERT_EQUAL(a, 4.0f);
69 
70     // Float16
71     setupBoxes(PF_A8B8G8R8, PF_FLOAT16_RGBA);
72     dst2.format = PF_A8B8G8R8;
73     unsigned int eob = src.getWidth()*4;
74 
75     PixelUtil::bulkPixelConversion(src, dst1);
76     PixelUtil::bulkPixelConversion(dst1, dst2);
77 
78     // Locate errors
79     std::stringstream s;
80     unsigned int x;
81     for(x=0; x<eob; x++) {
82         if(temp2[x] != randomData[x])
83             s << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) randomData[x]
84               << "!= " << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) temp2[x] << " ";
85     }
86 
87     // src and dst2 should match
88     CPPUNIT_ASSERT_MESSAGE("PF_FLOAT16_RGBA<->PF_A8B8G8R8 conversion was not lossless "+s.str(),
89         memcmp(src.data, dst2.data, eob) == 0);
90 }
91 
92 // Pure 32 bit float precision brute force pixel conversion; for comparison
naiveBulkPixelConversion(const PixelBox & src,const PixelBox & dst)93 void naiveBulkPixelConversion(const PixelBox &src, const PixelBox &dst)
94 {
95     uint8 *srcptr = static_cast<uint8*>(src.data);
96     uint8 *dstptr = static_cast<uint8*>(dst.data);
97     unsigned int srcPixelSize = PixelUtil::getNumElemBytes(src.format);
98     unsigned int dstPixelSize = PixelUtil::getNumElemBytes(dst.format);
99 
100     // Calculate pitches+skips in bytes
101     int srcRowSkipBytes = src.getRowSkip()*srcPixelSize;
102     int srcSliceSkipBytes = src.getSliceSkip()*srcPixelSize;
103 
104     int dstRowSkipBytes = dst.getRowSkip()*dstPixelSize;
105     int dstSliceSkipBytes = dst.getSliceSkip()*dstPixelSize;
106 
107 	// The brute force fallback
108 	float r,g,b,a;
109 	for(size_t z=src.front; z<src.back; z++)
110 	{
111 		for(size_t y=src.top; y<src.bottom; y++)
112 		{
113 			for(size_t x=src.left; x<src.right; x++)
114 			{
115 				PixelUtil::unpackColour(&r, &g, &b, &a, src.format, srcptr);
116 				PixelUtil::packColour(r, g, b, a, dst.format, dstptr);
117 				srcptr += srcPixelSize;
118 				dstptr += dstPixelSize;
119 			}
120 			srcptr += srcRowSkipBytes;
121 			dstptr += dstRowSkipBytes;
122 		}
123 		srcptr += srcSliceSkipBytes;
124 		dstptr += dstSliceSkipBytes;
125 	}
126 
127 }
128 
setupBoxes(PixelFormat srcFormat,PixelFormat dstFormat)129 void PixelFormatTests::setupBoxes(PixelFormat srcFormat, PixelFormat dstFormat)
130 {
131     unsigned int width = (size-4) / PixelUtil::getNumElemBytes(srcFormat);
132     unsigned int width2 = (size-4) / PixelUtil::getNumElemBytes(dstFormat);
133     if(width > width2)
134         width = width2;
135 
136     src = PixelBox(width, 1, 1, srcFormat, randomData);
137 	dst1 = PixelBox(width, 1, 1, dstFormat, temp);
138 	dst2 = PixelBox(width, 1, 1, dstFormat, temp2);
139 
140 }
141 
testCase(PixelFormat srcFormat,PixelFormat dstFormat)142 void PixelFormatTests::testCase(PixelFormat srcFormat, PixelFormat dstFormat)
143 {
144     setupBoxes(srcFormat, dstFormat);
145     // Check end of buffer
146     unsigned int eob = dst1.getWidth()*PixelUtil::getNumElemBytes(dstFormat);
147     temp[eob] = (unsigned char)0x56;
148     temp[eob+1] = (unsigned char)0x23;
149 
150     //std::cerr << "["+PixelUtil::getFormatName(srcFormat)+"->"+PixelUtil::getFormatName(dstFormat)+"]" << " " << eob << std::endl;
151 
152     // Do pack/unpacking with both naive and optimized version
153     PixelUtil::bulkPixelConversion(src, dst1);
154     naiveBulkPixelConversion(src, dst2);
155 
156     CPPUNIT_ASSERT_EQUAL(temp[eob], (unsigned char)0x56);
157     CPPUNIT_ASSERT_EQUAL(temp[eob+1], (unsigned char)0x23);
158 
159     std::stringstream s;
160     int x;
161     s << "src=";
162     for(x=0; x<16; x++)
163         s << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) randomData[x];
164     s << " dst=";
165     for(x=0; x<16; x++)
166         s << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) temp[x];
167     s << " dstRef=";
168     for(x=0; x<16; x++)
169         s << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) temp2[x];
170     s << " ";
171 
172     // Compare result
173 	StringUtil::StrStreamType msg;
174 	msg << "Conversion mismatch [" << PixelUtil::getFormatName(srcFormat) <<
175 		"->" << PixelUtil::getFormatName(dstFormat) << "] " << s.str();
176     CPPUNIT_ASSERT_MESSAGE(msg.str().c_str(),
177 		memcmp(dst1.data, dst2.data, eob) == 0);
178 }
179 
testBulkConversion()180 void PixelFormatTests::testBulkConversion()
181 {
182     // Self match
183     testCase(PF_A8R8G8B8, PF_A8R8G8B8);
184     // Optimized
185 	testCase(PF_A8R8G8B8,PF_A8B8G8R8);
186 	testCase(PF_A8R8G8B8,PF_B8G8R8A8);
187 	testCase(PF_A8R8G8B8,PF_R8G8B8A8);
188 	testCase(PF_A8B8G8R8,PF_A8R8G8B8);
189 	testCase(PF_A8B8G8R8,PF_B8G8R8A8);
190 	testCase(PF_A8B8G8R8,PF_R8G8B8A8);
191 	testCase(PF_B8G8R8A8,PF_A8R8G8B8);
192 	testCase(PF_B8G8R8A8,PF_A8B8G8R8);
193 	testCase(PF_B8G8R8A8,PF_R8G8B8A8);
194 	testCase(PF_R8G8B8A8,PF_A8R8G8B8);
195 	testCase(PF_R8G8B8A8,PF_A8B8G8R8);
196 	testCase(PF_R8G8B8A8,PF_B8G8R8A8);
197 
198     testCase(PF_A8B8G8R8, PF_L8);
199     testCase(PF_L8, PF_A8B8G8R8);
200     testCase(PF_A8R8G8B8, PF_L8);
201     testCase(PF_L8, PF_A8R8G8B8);
202     testCase(PF_B8G8R8A8, PF_L8);
203     testCase(PF_L8, PF_B8G8R8A8);
204     testCase(PF_L8, PF_L16);
205     testCase(PF_L16, PF_L8);
206     testCase(PF_R8G8B8, PF_B8G8R8);
207     testCase(PF_B8G8R8, PF_R8G8B8);
208     testCase(PF_B8G8R8, PF_R8G8B8);
209     testCase(PF_R8G8B8, PF_B8G8R8);
210     testCase(PF_R8G8B8, PF_A8R8G8B8);
211     testCase(PF_B8G8R8, PF_A8R8G8B8);
212     testCase(PF_R8G8B8, PF_A8B8G8R8);
213     testCase(PF_B8G8R8, PF_A8B8G8R8);
214     testCase(PF_R8G8B8, PF_B8G8R8A8);
215     testCase(PF_B8G8R8, PF_B8G8R8A8);
216 	testCase(PF_A8R8G8B8, PF_R8G8B8);
217 	testCase(PF_A8R8G8B8, PF_B8G8R8);
218 	testCase(PF_X8R8G8B8, PF_A8R8G8B8);
219 	testCase(PF_X8R8G8B8, PF_A8B8G8R8);
220 	testCase(PF_X8R8G8B8, PF_B8G8R8A8);
221 	testCase(PF_X8R8G8B8, PF_R8G8B8A8);
222 	testCase(PF_X8B8G8R8, PF_A8R8G8B8);
223 	testCase(PF_X8B8G8R8, PF_A8B8G8R8);
224 	testCase(PF_X8B8G8R8, PF_B8G8R8A8);
225 	testCase(PF_X8B8G8R8, PF_R8G8B8A8);
226 
227     //CPPUNIT_ASSERT_MESSAGE("Conversion mismatch", false);
228 }
229 
230