aboutsummaryrefslogtreecommitdiff
path: root/samples
diff options
context:
space:
mode:
authorHugues Evrard <hevrard@users.noreply.github.com>2019-01-28 17:06:16 +0000
committerdan sinclair <dj2@everburning.com>2019-01-28 12:06:16 -0500
commit970ba7a99eba1cd8d8a1ea10e4525db8b93fd284 (patch)
treee721902a817418e544d52eeb3cd7385ea214dd31 /samples
parentbca10fbe5f6fe21cae4c8cca0ccf0d07719c8670 (diff)
downloadamber-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.txt1
-rw-r--r--samples/amber.cc43
-rw-r--r--samples/ppm.cc65
-rw-r--r--samples/ppm.h36
-rw-r--r--samples/ppm_test.cc94
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