Initial commit
This commit is contained in:
276
engines/ags/tests/test_gfx.cpp
Normal file
276
engines/ags/tests/test_gfx.cpp
Normal file
@@ -0,0 +1,276 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/shared/debugging/out.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "common/debug.h"
|
||||
#include "ags/shared/core/platform.h"
|
||||
#include "ags/shared/gfx/gfx_def.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "ags/lib/allegro/color.h"
|
||||
#include "ags/shared/gfx/bitmap.h"
|
||||
#include "ags/shared/gfx/image.h"
|
||||
#include "ags/lib/allegro/surface.h"
|
||||
#include "ags/shared/debugging/debug_manager.h"
|
||||
#include "ags/globals.h"
|
||||
#include "graphics/managed_surface.h"
|
||||
#include "graphics/pixelformat.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
namespace GfxDef = AGS::Shared::GfxDef;
|
||||
using namespace AGS::Shared;
|
||||
|
||||
void Test_GfxSpeed(bool enableSimd, size_t blenderModeStart, size_t blenderModeEnd) {
|
||||
uint oldSimdFlags = _G(simd_flags);
|
||||
if (!enableSimd) _G(simd_flags) = AGS3::Globals::SIMD_NONE;
|
||||
if (enableSimd) debug("SIMD optimizations: true\n");
|
||||
else debug("SIMD optimizations: false\n");
|
||||
Bitmap *benchgfx32 = BitmapHelper::CreateBitmap(100, 100, 32);
|
||||
Bitmap *benchgfx16 = BitmapHelper::CreateBitmapCopy(benchgfx32, 16);
|
||||
Bitmap *benchgfx8 = BitmapHelper::CreateBitmap(100, 100, 8);
|
||||
Bitmap *dest32 = BitmapHelper::CreateBitmap(100, 100, 32);
|
||||
Bitmap *dest16 = BitmapHelper::CreateBitmap(100, 100, 16);
|
||||
Bitmap *dest8 = BitmapHelper::CreateBitmap(100, 100, 8);
|
||||
int benchRuns[] = {1000, 10000, 100000};
|
||||
int blenderModes[] = {kRgbToRgbBlender, kSourceAlphaBlender, kArgbToArgbBlender, kOpaqueBlenderMode, kTintLightBlenderMode};
|
||||
//const char *modeNames[] = {"RGB to RGB", "Source Alpha", "ARGB to ARGB", "Opaque", "Tint with Light"};
|
||||
Bitmap *destinations[] = {dest32, dest16, dest8};
|
||||
Bitmap *graphics[] = {benchgfx32, benchgfx16, benchgfx8};
|
||||
uint64 time = 0, numIters = 0, timeNotStretched = 0, numItersNotStretched = 0, timeCommon = 0, numItersCommon = 0;
|
||||
//int bpps[] = {32, 16, 8};
|
||||
if (blenderModeEnd >= sizeof(blenderModes) / sizeof(blenderModes[0])) blenderModeEnd = (sizeof(blenderModes) / sizeof(blenderModes[0])) - 1;
|
||||
for (int dest = 0; dest < 3; dest++) {
|
||||
for (int gfx = 0; gfx < 3; gfx++) {
|
||||
if (dest == 2 && gfx != 2) continue;
|
||||
for (size_t mode = blenderModeStart; mode <= blenderModeEnd; mode++) {
|
||||
for (int runs = 0; (size_t)runs < sizeof(benchRuns)/sizeof(int); runs++) {
|
||||
uint32 start, end;
|
||||
_G(_blender_mode) = (AGS3::BlenderMode)blenderModes[mode];
|
||||
//if (runs == 2) debug("Dest: %d bpp, Gfx: %d bpp, Blender: %s, Stretched: false, Iters: %d\n", bpps[dest], bpps[gfx], modeNames[mode], benchRuns[runs]);
|
||||
start = std::chrono::high_resolution_clock::now();
|
||||
for (int i = 0; i < benchRuns[runs]; i++)
|
||||
destinations[dest]->Blit(graphics[gfx], 0, 0, kBitmap_Transparency);
|
||||
end = std::chrono::high_resolution_clock::now();
|
||||
timeNotStretched += end - start;
|
||||
numItersNotStretched += benchRuns[runs];
|
||||
if (mode == kArgbToArgbBlender || mode == kRgbToRgbBlender || mode == kRgbToArgbBlender || mode == kArgbToRgbBlender) {
|
||||
timeCommon += end - start;
|
||||
numItersCommon += benchRuns[runs];
|
||||
}
|
||||
time += end - start;
|
||||
//if (runs == 2) debug("exec time (mills): %u\n\n", end - start);
|
||||
//if (runs == 2) debug("Dest: %d bpp, Gfx: %d bpp, Blender: %s, Stretched: true, Iters: %d\n", bpps[dest], bpps[gfx], modeNames[mode], benchRuns[runs]);
|
||||
start = std::chrono::high_resolution_clock::now();
|
||||
for (int i = 0; i < benchRuns[runs]; i++)
|
||||
destinations[dest]->StretchBlt(graphics[gfx], Rect(0, 0, 99, 99), kBitmap_Transparency);
|
||||
end = std::chrono::high_resolution_clock::now();
|
||||
time += end - start;
|
||||
numIters += benchRuns[runs] * 2;
|
||||
//if (runs == 2) debug("exec time (mills): %u\n\n", end - start);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug("Over all blender modes, pixel formats, and stretching sizes (%f) avg millis per call.", (double)time / (double)numIters);
|
||||
debug("Over all blender modes, pixel formats, but only unstretched (%f) avg millis per call.", (double)timeNotStretched / (double)numItersNotStretched);
|
||||
debug("Over most common blender modes, all pixel formats, but only unstretched (%f) avg millis per call.", (double)timeCommon / (double)numItersCommon);
|
||||
|
||||
delete benchgfx32;
|
||||
delete benchgfx16;
|
||||
delete benchgfx8;
|
||||
delete dest32;
|
||||
delete dest16;
|
||||
delete dest8;
|
||||
|
||||
if (!enableSimd) _G(simd_flags) = oldSimdFlags;
|
||||
}
|
||||
|
||||
void Test_BlenderModes() {
|
||||
constexpr int depth = 2;
|
||||
Graphics::ManagedSurface owner(16, 16, Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24));
|
||||
BITMAP dummy(&owner);
|
||||
Graphics::ManagedSurface owner16(16, 16, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
|
||||
BITMAP dummy16(&owner16);
|
||||
Graphics::ManagedSurface ownerDest(16, 16, Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24));
|
||||
BITMAP dummyDest(&ownerDest);
|
||||
Graphics::ManagedSurface ownerDest16(16, 16, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
|
||||
BITMAP dummyDest16(&ownerDest16);
|
||||
for (int blenderMode = (int)kSourceAlphaBlender; blenderMode <= (int)kTintLightBlenderMode; blenderMode++) {
|
||||
_G(_blender_mode) = (BlenderMode)blenderMode;
|
||||
for (int srcR = 0; srcR < 255; srcR += (1 << (8 - depth))) {
|
||||
for (int srcG = 0; srcG < 255; srcG += (1 << (8 - depth))) {
|
||||
for (int srcB = 0; srcB < 255; srcB += (1 << (8 - depth))) {
|
||||
for (int srcA = 0; srcA < 255; srcA += (1 << (8 - depth))) {
|
||||
for (int destR = 0; destR < 255; destR += (1 << (8 - depth))) {
|
||||
for (int destG = 0; destG < 255; destG += (1 << (8 - depth))) {
|
||||
for (int destB = 0; destB < 255; destB += (1 << (8 - depth))) {
|
||||
for (int destA = 0; destA < 255; destA += (1 << (8 - depth))) {
|
||||
for (uint32 alpha = 0; alpha < 255; alpha += (1 << (8 - depth))) {
|
||||
// First run the non-vectorized version of the code
|
||||
uint32 controlCol = 0, simdCol = 0;
|
||||
uint16 control2bppCol = 0, simd2bppCol = 0;
|
||||
uint8 a, r, g, b, a16, r16, g16, b16;
|
||||
a = r = g = b = a16 = r16 = g16 = b16 = 0;
|
||||
|
||||
auto printInfo = [&]() {
|
||||
debug("src argb: %d, %d, %d, %d dest argb: %d, %d, %d, %d a: %d", srcA, srcR, srcG, srcB, destA, destR, destG, destB, alpha);
|
||||
switch ((BlenderMode)blenderMode) {
|
||||
case kSourceAlphaBlender: debug("blenderMode: kSourceAlphaBlender"); break;
|
||||
case kArgbToArgbBlender: debug("blenderMode: kArgbToArgbBlender"); break;
|
||||
case kArgbToRgbBlender: debug("blenderMode: kArgbToRgbBlender"); break;
|
||||
case kRgbToArgbBlender: debug("blenderMode: kRgbToArgbBlender"); break;
|
||||
case kRgbToRgbBlender: debug("blenderMode: kRgbToRgbBlender"); break;
|
||||
case kAlphaPreservedBlenderMode: debug("blenderMode: kAlphaPreservedBlenderMode"); break;
|
||||
case kOpaqueBlenderMode: debug("blenderMode: kOpaqueBlenderMode"); break;
|
||||
case kAdditiveBlenderMode: debug("blenderMode: kAdditiveBlenderMode"); break;
|
||||
case kTintBlenderMode: debug("blenderMode: kTintBlenderMode"); break;
|
||||
case kTintLightBlenderMode: debug("blenderMode: kTintLightBlenderMode"); break;
|
||||
}
|
||||
debug("controlCol %x argb: %d, %d, %d, %d", controlCol, a, r, g, b);
|
||||
debug("simdCol %x argb: %d, %d, %d, %d", simdCol, (simdCol >> 24), ((simdCol >> 16) & 0xff), ((simdCol >> 8) & 0xff), (simdCol & 0xff));
|
||||
debug("control2bppCol %x rgb: %d, %d, %d", control2bppCol, r16, g16, b16);
|
||||
debug("simd2bppCol %x rgb: %d, %d, %d", simd2bppCol, (simd2bppCol >> 11), ((simd2bppCol >> 5) & 0x3f), (simd2bppCol & 0x1f));
|
||||
};
|
||||
|
||||
uint oldSimdFlags = _G(simd_flags);
|
||||
_G(simd_flags) = AGS3::Globals::SIMD_NONE;
|
||||
*(uint32 *)dummy.getBasePtr(0, 0) = dummy.format.ARGBToColor(srcA, srcR, srcG, srcB);
|
||||
*(uint32 *)dummyDest.getBasePtr(0, 0) = dummyDest.format.ARGBToColor(destA, destR, destG, destB);
|
||||
dummyDest.draw(&dummy, Common::Rect(16, 16), 0, 0, false, false, false, alpha);
|
||||
controlCol = dummyDest.getpixel(0, 0);
|
||||
dummyDest.format.colorToARGB(dummyDest.getpixel(0, 0), a, r, g, b);
|
||||
|
||||
*(uint16 *)dummy16.getBasePtr(0, 0) = dummy16.format.ARGBToColor(srcA, srcR, srcG, srcB);
|
||||
*(uint16 *)dummyDest16.getBasePtr(0, 0) = dummyDest16.format.ARGBToColor(destA, destR, destG, destB);
|
||||
dummyDest16.draw(&dummy16, Common::Rect(16, 16), 0, 0, false, false, false, alpha);
|
||||
control2bppCol = dummyDest16.getpixel(0, 0);
|
||||
dummyDest16.format.colorToARGB(dummyDest16.getpixel(0, 0), a16, r16, g16, b16);
|
||||
a16 >>= 3; r16 >>= 3; g16 >>= 2; b16 >>= 3;
|
||||
_G(simd_flags) = oldSimdFlags;
|
||||
|
||||
*(uint32 *)dummy.getBasePtr(0, 0) = dummy.format.ARGBToColor(srcA, srcR, srcG, srcB);
|
||||
*(uint32 *)dummyDest.getBasePtr(0, 0) = dummyDest.format.ARGBToColor(destA, destR, destG, destB);
|
||||
dummyDest.draw(&dummy, Common::Rect(16, 16), 0, 0, false, false, false, alpha);
|
||||
simdCol = dummyDest.getpixel(0, 0);
|
||||
|
||||
*(uint16 *)dummy16.getBasePtr(0, 0) = dummy16.format.ARGBToColor(srcA, srcR, srcG, srcB);
|
||||
*(uint16 *)dummyDest16.getBasePtr(0, 0) = dummyDest16.format.ARGBToColor(destA, destR, destG, destB);
|
||||
dummyDest16.draw(&dummy16, Common::Rect(16, 16), 0, 0, false, false, false, alpha);
|
||||
simd2bppCol = dummyDest16.getpixel(0, 0);
|
||||
|
||||
int tolerance, tolerance16;
|
||||
switch ((BlenderMode)blenderMode) {
|
||||
// These need to be IDENTICAL for lamplight city to work
|
||||
// It would be nice to get tolerance16 down to 0 though...
|
||||
case kRgbToRgbBlender:
|
||||
case kArgbToRgbBlender:
|
||||
case kSourceAlphaBlender:
|
||||
case kAlphaPreservedBlenderMode:
|
||||
tolerance = 0;
|
||||
tolerance16 = 1;
|
||||
break;
|
||||
|
||||
// These can be 1 or 2 off, as long as they look the same
|
||||
case kArgbToArgbBlender:
|
||||
case kRgbToArgbBlender:
|
||||
case kOpaqueBlenderMode:
|
||||
case kAdditiveBlenderMode:
|
||||
tolerance = 1;
|
||||
tolerance16 = 1;
|
||||
break;
|
||||
|
||||
case kTintBlenderMode:
|
||||
case kTintLightBlenderMode:
|
||||
tolerance = 2;
|
||||
tolerance16 = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
tolerance = 0;
|
||||
}
|
||||
if (std::abs((int)a - (int)(simdCol >> 24)) > tolerance) {
|
||||
printInfo();
|
||||
assert(false && "a is over the tolerance");
|
||||
}
|
||||
if (std::abs((int)r - (int)((simdCol >> 16) & 0xff)) > tolerance) {
|
||||
printInfo();
|
||||
assert(false && "r is over the tolerance");
|
||||
}
|
||||
if (std::abs((int)g - (int)((simdCol >> 8) & 0xff)) > tolerance) {
|
||||
printInfo();
|
||||
assert(false && "g is over the tolerance");
|
||||
}
|
||||
if (std::abs((int)b - (int)(simdCol & 0xff)) > tolerance) {
|
||||
printInfo();
|
||||
assert(false && "b is over the tolerance");
|
||||
}
|
||||
if (std::abs((int)b16 - (int)(simd2bppCol & 0x1f)) > tolerance16) {
|
||||
printInfo();
|
||||
assert(false && "b16 is over the tolerance");
|
||||
}
|
||||
if (std::abs((int)g16 - (int)((simd2bppCol >> 5) & 0x3f)) > tolerance16) {
|
||||
printInfo();
|
||||
assert(false && "g16 is over the tolerance");
|
||||
}
|
||||
if (std::abs((int)r16 - (int)(simd2bppCol >> 11)) > tolerance16) {
|
||||
printInfo();
|
||||
assert(false && "r16 is over the tolerance");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Test_GfxTransparency() {
|
||||
// Test that every transparency which is a multiple of 10 is converted
|
||||
// forth and back without losing precision
|
||||
const size_t arr_sz = 11;
|
||||
const int trans100[arr_sz] = { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
|
||||
int trans255[arr_sz] = { 0 };
|
||||
int trans100_back[arr_sz] = { 0 };
|
||||
|
||||
for (size_t i = 0; i < arr_sz; ++i) {
|
||||
trans255[i] = GfxDef::Trans100ToLegacyTrans255(trans100[i]);
|
||||
trans100_back[i] = GfxDef::LegacyTrans255ToTrans100(trans255[i]);
|
||||
assert(trans100[i] == trans100_back[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Test_Gfx() {
|
||||
Test_GfxTransparency();
|
||||
#if (defined(SCUMMVM_AVX2) || defined(SCUMMVM_SSE2) || defined(SCUMMVM_NEON)) && defined(SLOW_TESTS)
|
||||
Test_BlenderModes();
|
||||
// This could take a LONG time
|
||||
Test_GfxSpeed(true, kSourceAlphaBlender, kTintLightBlenderMode);
|
||||
Test_GfxSpeed(false, kSourceAlphaBlender, kTintLightBlenderMode);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
Reference in New Issue
Block a user