diff --git a/samples/Android.mk b/samples/Android.mk index 9d8033e7b..946e12754 100644 --- a/samples/Android.mk +++ b/samples/Android.mk @@ -21,6 +21,7 @@ LOCAL_SRC_FILES:= \ amber.cc \ config_helper.cc \ config_helper_vulkan.cc \ + farbfeld.cc \ log.cc \ ppm.cc LOCAL_C_INCLUDES := $(LOCAL_PATH)/.. $(LOCAL_PATH)/../include diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index c71291aa9..6bd913f19 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -17,6 +17,7 @@ include_directories("${PROJECT_SOURCE_DIR}/include") set(AMBER_SOURCES amber.cc config_helper.cc + farbfeld.cc log.cc ppm.cc ${CMAKE_BINARY_DIR}/src/build-versions.h.fake diff --git a/samples/amber.cc b/samples/amber.cc index 6b5ceacf1..b31fb51a6 100644 --- a/samples/amber.cc +++ b/samples/amber.cc @@ -23,6 +23,7 @@ #include "amber/amber.h" #include "amber/recipe.h" #include "samples/config_helper.h" +#include "samples/farbfeld.h" #include "samples/ppm.h" #include "src/build-versions.h" #include "src/make_unique.h" @@ -53,7 +54,7 @@ const char kUsage[] = R"(Usage: amber [options] SCRIPT [SCRIPTS...] -s -- Print summary of pass/failure. -d -- Disable validation layers. -t -- The target SPIR-V environment. Defaults to SPV_ENV_UNIVERSAL_1_0. - -i -- Write rendering to as a PPM image. + -i -- Write rendering to , as a farbfeld image if filename ends with '.ff', as a PPM image otherwise. -b -- Write contents of a UBO or SSBO to . -B -- Index of buffer to write. Defaults buffer 0. -e -- Specify graphics engine: vulkan, dawn. Default is vulkan. @@ -324,8 +325,17 @@ int main(int argc, const char** argv) { std::string image; for (amber::BufferInfo buffer_info : amber_options.extractions) { if (buffer_info.buffer_name == "framebuffer") { - std::tie(result, image) = ppm::ConvertToPPM( - buffer_info.width, buffer_info.height, buffer_info.values); + // Image encoding: use farbfeld if image filename ends with ".ff", + // otherwise default to PPM. + if (options.image_filename.compare( + options.image_filename.length() - 4, + options.image_filename.length(), ".ff")) { + std::tie(result, image) = farbfeld::ConvertToFarbfeld( + buffer_info.width, buffer_info.height, buffer_info.values); + } else { + std::tie(result, image) = ppm::ConvertToPPM( + buffer_info.width, buffer_info.height, buffer_info.values); + } break; } } diff --git a/samples/farbfeld.cc b/samples/farbfeld.cc new file mode 100644 index 000000000..30c6f9c79 --- /dev/null +++ b/samples/farbfeld.cc @@ -0,0 +1,83 @@ +// Copyright 2019 The Amber Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "samples/farbfeld.h" + +#include + +#include "amber/result.h" +#include "amber/value.h" + +namespace farbfeld { + +namespace { + +char byte0(uint32_t word) { + return static_cast(word); +} + +char byte1(uint32_t word) { + return static_cast(word >> 8); +} + +char byte2(uint32_t word) { + return static_cast(word >> 16); +} + +char byte3(uint32_t word) { + return static_cast(word >> 24); +} + +} // namespace + +std::pair ConvertToFarbfeld( + uint32_t width, + uint32_t height, + const std::vector& values) { + assert(values.size() == width * height); + + // Farbfeld format details: https://tools.suckless.org/farbfeld/ + + // Farbfeld header + std::string image = "farbfeld"; + // 32 bits big endian unsigned integers for width, and then height + image.push_back(byte3(width)); + image.push_back(byte2(width)); + image.push_back(byte1(width)); + image.push_back(byte0(width)); + image.push_back(byte3(height)); + image.push_back(byte2(height)); + image.push_back(byte1(height)); + image.push_back(byte0(height)); + + // Farbfeld data + for (amber::Value value : values) { + const uint32_t pixel = value.AsUint32(); + // We assume R8G8B8A8_UINT here. Note the zero char is added to fill up the + // 16 bits available for each channel. + const char zero = static_cast(0); + image.push_back(byte0(pixel)); // R + image.push_back(zero); + image.push_back(byte1(pixel)); // G + image.push_back(zero); + image.push_back(byte2(pixel)); // B + image.push_back(zero); + image.push_back(byte3(pixel)); // A + image.push_back(zero); + } + + return std::make_pair(amber::Result(), image); +} + +} // namespace farbfeld diff --git a/samples/farbfeld.h b/samples/farbfeld.h new file mode 100644 index 000000000..238e58779 --- /dev/null +++ b/samples/farbfeld.h @@ -0,0 +1,36 @@ +// Copyright 2019 The Amber Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SAMPLES_FARBFELD_H_ +#define SAMPLES_FARBFELD_H_ + +#include +#include +#include + +#include "amber/amber.h" + +namespace farbfeld { + +/// Converts the image of dimensions |width| and |height| and with pixels stored +/// in row-major order in |values| with format R8G8B8A8 into farbfeld format, +/// returning the farbfeld binary as a string. +std::pair ConvertToFarbfeld( + uint32_t width, + uint32_t height, + const std::vector& values); + +} // namespace farbfeld + +#endif // SAMPLES_FARBFELD_H__