Почему библиотеки не победят "чистый" Си
Медленны таки контейнеры STL или нет? Смотря, как Вы их умеете готовить используете.
Ниже показан код, демонстрирующий одну из типовых операций при разработке игр - MIP-текстурирование 32-битного изображения RGBA размерностью 512 × 512 пикселей.
Консольный код проверялся в пустом консольном проекте Visual Studio 2019. Сначала результаты, как там насчёт того, что "старые" Си-массивы неактуальны? :)
std::array: InitImage: 23.216800 ms MakeMips: 41.095700 ms std::vector: InitImage: 25.524400 ms MakeMips: 41.857400 ms c array: InitImage: 3.317600 ms MakeMips: 6.030900 ms
И листинг:
// the size of the image that is made into mips #define IMAGE_SIZE() 512 typedef float ChannelType; #include <cstdio> #include <array> #include <vector> #include <chrono> struct ScopedTimer { ScopedTimer(const char* label) { printf("%s: ", label); m_start = std::chrono::high_resolution_clock::now(); } ~ScopedTimer() { std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now(); std::chrono::duration<double> time_span = std::chrono::duration_cast<std::chrono::duration<double>>(end - m_start); printf("%f ms\n", time_span.count() * 1000.0f); } std::chrono::high_resolution_clock::time_point m_start; }; // calculate the total number of pixels needed to hold the image of size IMAGE_SIZE() as well as all the mips constexpr size_t TotalPixelsMipped() { size_t ret = 0; size_t size = IMAGE_SIZE(); while (size) { ret += size * size; size /= 2; } return ret; } constexpr size_t TotalChannelsMipped() { // RGBA return TotalPixelsMipped() * 4; } constexpr size_t NumMips() { size_t ret = 0; size_t size = IMAGE_SIZE(); while (size) { ret++; size /= 2; } return ret; } void GetMipInfo(size_t desiredMipIndex, size_t& offset, size_t& width) { offset = 0; width = IMAGE_SIZE(); for (size_t mipIndex = 0; mipIndex < desiredMipIndex; ++mipIndex) { offset += width * width * 4; width /= 2; } } template <typename T> void MakeMip(T& image, size_t mipIndex) { size_t srcOffset; size_t srcWidth; GetMipInfo(mipIndex - 1, srcOffset, srcWidth); size_t destOffset; size_t destWidth; GetMipInfo(mipIndex, destOffset, destWidth); for (size_t destY = 0; destY < destWidth; ++destY) { for (size_t destX = 0; destX < destWidth; ++destX) { for (size_t channel = 0; channel < 4; ++channel) { // 2x2 box filter source mip pixels float value = float(image[((destY * 2 + 0) * srcWidth + destX * 2 + 0) * 4 + srcOffset] + channel) + float(image[((destY * 2 + 0) * srcWidth + destX * 2 + 1) * 4 + srcOffset] + channel) + float(image[((destY * 2 + 1) * srcWidth + destX * 2 + 0) * 4 + srcOffset] + channel) + float(image[((destY * 2 + 1) * srcWidth + destX * 2 + 1) * 4 + srcOffset] + channel); image[destOffset] = ChannelType(value / 4.0f); destOffset++; } } } } template<typename T> void MakeMips(T& image) { size_t mipCount = NumMips(); for (size_t mipIndex = 1; mipIndex < mipCount; ++mipIndex) MakeMip(image, mipIndex); } template<typename T> void InitImage(T& image) { memset(&image[0], 0, TotalChannelsMipped() * sizeof(float)); // It doesn't matter what we put into the image since we aren't ever looking at it, but initializing it anyhow. size_t i = 0; for (size_t y = 0; y < IMAGE_SIZE(); ++y) { for (size_t x = 0; x < IMAGE_SIZE(); ++x) { image[i * 4 + 0] = ChannelType(x % 256); image[i * 4 + 1] = ChannelType(y % 256); image[i * 4 + 2] = ChannelType(0); image[i * 4 + 3] = ChannelType(255); i++; } } } int main(void) { // std::array { std::array<ChannelType, TotalChannelsMipped()>* array_ptr = new std::array<ChannelType, TotalChannelsMipped()>; std::array<ChannelType, TotalChannelsMipped()>& array = *array_ptr; printf("std::array:\n"); { ScopedTimer timer("InitImage"); InitImage(array); } { ScopedTimer timer("MakeMips"); MakeMips(array); } delete array_ptr; } // std::vector { std::vector <ChannelType> vector; printf("\nstd::vector:\n"); { ScopedTimer timer("InitImage"); vector.resize(TotalChannelsMipped()); InitImage(vector); } { ScopedTimer timer("MakeMips"); MakeMips(vector); } } // c array { ChannelType* carray = nullptr; printf("\nc array:\n"); { ScopedTimer timer("InitImage"); carray = (ChannelType*)malloc(sizeof(ChannelType) * TotalChannelsMipped()); InitImage(carray); } { ScopedTimer timer("MakeMips"); MakeMips(carray); } free(carray); } system("pause"); return 0; }
16.11.2019, 19:53 [1007 просмотров]