diff options
author | Hugues Evrard <hevrard@users.noreply.github.com> | 2019-01-28 17:06:16 +0000 |
---|---|---|
committer | dan sinclair <dj2@everburning.com> | 2019-01-28 12:06:16 -0500 |
commit | 970ba7a99eba1cd8d8a1ea10e4525db8b93fd284 (patch) | |
tree | e721902a817418e544d52eeb3cd7385ea214dd31 /samples | |
parent | bca10fbe5f6fe21cae4c8cca0ccf0d07719c8670 (diff) | |
download | amber-970ba7a99eba1cd8d8a1ea10e4525db8b93fd284.tar.gz |
Add framebuffer dump in PPM format (#227)
This CL plumbs through the ability to dump the framebuffer into a PPM image.
Diffstat (limited to 'samples')
-rw-r--r-- | samples/CMakeLists.txt | 1 | ||||
-rw-r--r-- | samples/amber.cc | 43 | ||||
-rw-r--r-- | samples/ppm.cc | 65 | ||||
-rw-r--r-- | samples/ppm.h | 36 | ||||
-rw-r--r-- | samples/ppm_test.cc | 94 |
5 files changed, 231 insertions, 8 deletions
diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 4357cb4..8bcc6f8 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -18,6 +18,7 @@ set(AMBER_SOURCES amber.cc config_helper.cc log.cc + ppm.cc ${CMAKE_BINARY_DIR}/src/build-versions.h.fake ) diff --git a/samples/amber.cc b/samples/amber.cc index 4d772ab..fc69f44 100644 --- a/samples/amber.cc +++ b/samples/amber.cc @@ -14,6 +14,7 @@ #include <cassert> #include <cstdlib> +#include <fstream> #include <iostream> #include <set> #include <utility> @@ -22,6 +23,7 @@ #include "amber/amber.h" #include "amber/recipe.h" #include "samples/config_helper.h" +#include "samples/ppm.h" #include "src/build-versions.h" #include "src/make_unique.h" @@ -247,26 +249,51 @@ int main(int argc, const char** argv) { amber_options.config = config.get(); + if (!options.buffer_filename.empty()) { + // TODO(dsinclair): Write buffer file + assert(false); + } + + if (!options.image_filename.empty()) { + amber::BufferInfo buffer_info; + buffer_info.buffer_name = "framebuffer"; + amber_options.extractions.push_back(buffer_info); + } + for (const auto& recipe_data_elem : recipe_data) { const auto* recipe = recipe_data_elem.recipe.get(); const auto& file = recipe_data_elem.file; amber::Amber am; - result = am.Execute(recipe, amber_options); + result = am.Execute(recipe, &amber_options); if (!result.IsSuccess()) { std::cerr << file << ": " << result.Error() << std::endl; failures.push_back(file); continue; } - if (!options.buffer_filename.empty()) { - // TODO(dsinclair): Write buffer file - assert(false); - } - if (!options.image_filename.empty()) { - // TODO(dsinclair): Write image file - assert(false); + 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); + break; + } + } + if (!result.IsSuccess()) { + std::cerr << result.Error() << std::endl; + continue; + } + std::ofstream image_file; + image_file.open(options.image_filename, std::ios::out | std::ios::binary); + if (!image_file.is_open()) { + std::cerr << "Cannot open file for image dump: "; + std::cerr << options.image_filename << std::endl; + continue; + } + image_file << image; + image_file.close(); } } diff --git a/samples/ppm.cc b/samples/ppm.cc new file mode 100644 index 0000000..5602118 --- /dev/null +++ b/samples/ppm.cc @@ -0,0 +1,65 @@ +// 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/ppm.h" + +#include <cassert> + +#include "amber/result.h" +#include "amber/value.h" + +namespace ppm { + +namespace { + +char byte0(uint32_t word) { + return static_cast<char>(word); +} + +char byte1(uint32_t word) { + return static_cast<char>(word >> 8); +} + +char byte2(uint32_t word) { + return static_cast<char>(word >> 16); +} + +} // namespace + +std::pair<amber::Result, std::string> ConvertToPPM( + uint32_t width, + uint32_t height, + const std::vector<amber::Value>& values) { + assert(values.size() == width * height); + + // Write PPM header + const uint32_t maximum_color_value = 255; + std::string image = "P6\n"; + image += std::to_string(width) + " " + std::to_string(height) + "\n"; + image += std::to_string(maximum_color_value) + "\n"; + + // Write PPM data + for (amber::Value value : values) { + const uint32_t pixel = value.AsUint32(); + // We assume R8G8B8A8_UINT here: + image.push_back(byte0(pixel)); // R + image.push_back(byte1(pixel)); // G + image.push_back(byte2(pixel)); // B + // PPM does not support alpha channel + } + + return std::make_pair(amber::Result(), image); +} + +} // namespace ppm diff --git a/samples/ppm.h b/samples/ppm.h new file mode 100644 index 0000000..0eb1f8e --- /dev/null +++ b/samples/ppm.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_PPM_H_ +#define SAMPLES_PPM_H_ + +#include <string> +#include <utility> +#include <vector> + +#include "amber/amber.h" + +namespace ppm { + +/// Converts the image of dimensions |width| and |height| and with pixels stored +/// in row-major order in |values| with format R8G8B8A8 into PPM format, +/// returning the PPM binary as a string. +std::pair<amber::Result, std::string> ConvertToPPM( + uint32_t width, + uint32_t height, + const std::vector<amber::Value>& values); + +} // namespace ppm + +#endif // SAMPLES_PPM_H_ diff --git a/samples/ppm_test.cc b/samples/ppm_test.cc new file mode 100644 index 0000000..9821455 --- /dev/null +++ b/samples/ppm_test.cc @@ -0,0 +1,94 @@ +// 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 "src/ppm.h" + +#include <algorithm> +#include <cstring> +#include <utility> +#include <vector> + +#include "amber/result.h" +#include "gtest/gtest.h" +#include "src/make_unique.h" + +namespace amber { +namespace { + +const uint8_t kExpectedPPM[] = { + 0x50, 0x36, 0x0a, 0x31, 0x32, 0x20, 0x36, 0x0a, 0x32, 0x35, 0x35, 0x0a, + 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, + 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, + 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, + 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff}; + +} // namespace + +using PpmTest = testing::Test; + +TEST_F(PpmTest, ConvertToPPM) { + const uint32_t width = 12; + const uint32_t height = 6; + + std::vector<amber::Value> data; + + const uint32_t MaskRed = 0x000000FF; + const uint32_t MaskBlue = 0x0000FF00; + const uint32_t MaskAplha = 0xFF000000; + + for (uint32_t y = 0; y < height; ++y) { + for (uint32_t x = 0; x < width; ++x) { + uint32_t pixel = MaskAplha; + if (x < width / 2) { + pixel |= MaskRed; + } else { + pixel |= MaskBlue; + } + if (y > height / 2) { + // invert colors + pixel = ~pixel; + // reset alpha to 1 + pixel |= MaskAplha; + } + v.SetIntValue(static_cast<uint64_t>(pixel)); + data.push_back(v); + } + } + + amber::Result r; + std::string image; + std::tie(r, image) = ConvertToPPM(width, height, &data); + + EXPECT_TRUE(r.IsSuccess()); + + // Compare + EXPECT_EQ(image.size(), sizeof(kExpectedPPM)); + EXPECT_EQ(std::memcmp(image.c_str(), kExpectedPPM, sizeof(kExpectedPPM)), 0); +} + +} // namespace amber |