<commit_before>#include "Profiling_Service.hpp"

#include "mmcore/MegaMolGraph.h"
#include "mmcore/view/AbstractViewInterface.h"
#include "mmcore/view/CameraSerializer.h"

#include "LuaCallbacksCollection.h"

namespace megamol {
namespace frontend {

bool Profiling_Service::init(void* configPtr) {
    _providedResourceReferences = {{"PerformanceManager", _perf_man}};

#ifdef PROFILING
    const auto conf = static_cast<Config*>(configPtr);
    if (conf != nullptr && !conf->log_file.empty()) {
        log_file = std::ofstream(conf->log_file, std::ofstream::trunc);
        // header
        log_file << "frame;parent;name;comment;frame_index;api;type;time (ms)" << std::endl;
        _perf_man.subscribe_to_updates([&](const frontend_resources::PerformanceManager::frame_info& fi) {
            auto frame = fi.frame;
            for (auto& e : fi.entries) {
                auto conf = _perf_man.lookup_config(e.handle);
                auto name = conf.name;
                auto parent = _perf_man.lookup_parent(e.handle);
                auto comment = conf.comment;
                std::string time_string;
                const auto dur = std::chrono::duration<double, std::milli>(e.timestamp.time_since_epoch());
                time_string = std::to_string(dur.count());

                log_file << frame << ";" << parent << ";" << name << ";" << comment << ";" << e.frame_index << ";"
                         << megamol::frontend_resources::PerformanceManager::query_api_string(e.api) << ";"
                         << megamol::frontend_resources::PerformanceManager::entry_type_string(e.type) << ";"
                         << time_string << std::endl;
            }
        });
    }
#endif

    _requestedResourcesNames = {"RegisterLuaCallbacks", "MegaMolGraph", "RenderNextFrame"};

    return true;
}

void Profiling_Service::close() {
#ifdef PROFILING
    if (log_file.is_open()) {
        log_file.close();
    }
#endif
}

void Profiling_Service::updateProvidedResources() {
    _perf_man.startFrame();
}

void Profiling_Service::resetProvidedResources() {
    _perf_man.endFrame();
}

void Profiling_Service::fill_lua_callbacks() {
    frontend_resources::LuaCallbacksCollection callbacks;

    auto& graph = const_cast<core::MegaMolGraph&>(_requestedResourcesReferences[1].getResource<core::MegaMolGraph>());
    auto& render_next_frame = _requestedResourcesReferences[2].getResource<std::function<bool()>>();

    callbacks.add<frontend_resources::LuaCallbacksCollection::StringResult, std::string, std::string, int>(
        "mmGenerateCameraPositions", "(string entrypoint, string camera_path_pattern, uint num_samples)",
        {[&graph](std::string entrypoint, std::string camera_path_pattern,
             int num_samples) -> frontend_resources::LuaCallbacksCollection::StringResult {
            auto entry = graph.FindModule(entrypoint);
            if (!entry)
                return frontend_resources::LuaCallbacksCollection::Error{"could not find entrypoint"};
            auto view = std::dynamic_pointer_cast<core::view::AbstractViewInterface>(entry);
            if (!view)
                return frontend_resources::LuaCallbacksCollection::Error{"requested entrypoint is not a view"};
            auto camera_samples = view->SampleCameraScenes(camera_path_pattern, num_samples);
            if (camera_samples.empty())
                return frontend_resources::LuaCallbacksCollection::Error{"could not sample camera"};
            return frontend_resources::LuaCallbacksCollection::StringResult{camera_samples};
        }});

    callbacks.add<frontend_resources::LuaCallbacksCollection::StringResult, std::string, std::string, int>("mmProfile",
        "(string entrypoint, string cameras, unsigned int num_frames)",
        {[&graph, &render_next_frame](std::string entrypoint, std::string cameras,
             int num_frames) -> frontend_resources::LuaCallbacksCollection::StringResult {
            auto entry = graph.FindModule(entrypoint);
            if (!entry)
                return frontend_resources::LuaCallbacksCollection::Error{"could not find entrypoint"};
            auto view = std::dynamic_pointer_cast<core::view::AbstractViewInterface>(entry);
            if (!view)
                return frontend_resources::LuaCallbacksCollection::Error{"requested entrypoint is not a view"};

            auto serializer = core::view::CameraSerializer();
            std::vector<core::view::Camera> cams;
            serializer.deserialize(cams, cameras);

            auto const old_cam = view->GetCamera();

            uint64_t tot_num_frames = num_frames * cams.size();

            auto const tp_start = std::chrono::system_clock::now();
            for (auto const& cam : cams) {
                view->SetCamera(cam);
                for (unsigned int f_idx = 0; f_idx < num_frames; ++f_idx) {
                    render_next_frame();
                }
            }
            auto const tp_end = std::chrono::system_clock::now();

            view->SetCamera(old_cam);

            auto const duration = tp_end - tp_start;

            auto const time_in_ms = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();

            auto const time_per_frame = static_cast<float>(time_in_ms) / static_cast<float>(tot_num_frames);

            std::stringstream sstr;
            sstr << "Total Number of Frames: " << tot_num_frames
                 << "; Elapsed Time (ms): " << std::chrono::duration_cast<std::chrono::milliseconds>(duration).count()
                 << "; Time per Frame (ms): " << time_per_frame;

            return frontend_resources::LuaCallbacksCollection::StringResult{sstr.str()};
        }});

    auto& register_callbacks =
        _requestedResourcesReferences[0]
            .getResource<std::function<void(frontend_resources::LuaCallbacksCollection const&)>>();

    register_callbacks(callbacks);
}

} // namespace frontend
} // namespace megamol
<commit_msg>csv output<commit_after>#include "Profiling_Service.hpp"

#include "mmcore/MegaMolGraph.h"
#include "mmcore/view/AbstractViewInterface.h"
#include "mmcore/view/CameraSerializer.h"

#include "LuaCallbacksCollection.h"

namespace megamol {
namespace frontend {

bool Profiling_Service::init(void* configPtr) {
    _providedResourceReferences = {{"PerformanceManager", _perf_man}};

#ifdef PROFILING
    const auto conf = static_cast<Config*>(configPtr);
    if (conf != nullptr && !conf->log_file.empty()) {
        log_file = std::ofstream(conf->log_file, std::ofstream::trunc);
        // header
        log_file << "frame;parent;name;comment;frame_index;api;type;time (ms)" << std::endl;
        _perf_man.subscribe_to_updates([&](const frontend_resources::PerformanceManager::frame_info& fi) {
            auto frame = fi.frame;
            for (auto& e : fi.entries) {
                auto conf = _perf_man.lookup_config(e.handle);
                auto name = conf.name;
                auto parent = _perf_man.lookup_parent(e.handle);
                auto comment = conf.comment;
                std::string time_string;
                const auto dur = std::chrono::duration<double, std::milli>(e.timestamp.time_since_epoch());
                time_string = std::to_string(dur.count());

                log_file << frame << ";" << parent << ";" << name << ";" << comment << ";" << e.frame_index << ";"
                         << megamol::frontend_resources::PerformanceManager::query_api_string(e.api) << ";"
                         << megamol::frontend_resources::PerformanceManager::entry_type_string(e.type) << ";"
                         << time_string << std::endl;
            }
        });
    }
#endif

    _requestedResourcesNames = {"RegisterLuaCallbacks", "MegaMolGraph", "RenderNextFrame"};

    return true;
}

void Profiling_Service::close() {
#ifdef PROFILING
    if (log_file.is_open()) {
        log_file.close();
    }
#endif
}

void Profiling_Service::updateProvidedResources() {
    _perf_man.startFrame();
}

void Profiling_Service::resetProvidedResources() {
    _perf_man.endFrame();
}

void Profiling_Service::fill_lua_callbacks() {
    frontend_resources::LuaCallbacksCollection callbacks;

    auto& graph = const_cast<core::MegaMolGraph&>(_requestedResourcesReferences[1].getResource<core::MegaMolGraph>());
    auto& render_next_frame = _requestedResourcesReferences[2].getResource<std::function<bool()>>();

    callbacks.add<frontend_resources::LuaCallbacksCollection::StringResult, std::string, std::string, int>(
        "mmGenerateCameraPositions", "(string entrypoint, string camera_path_pattern, uint num_samples)",
        {[&graph](std::string entrypoint, std::string camera_path_pattern,
             int num_samples) -> frontend_resources::LuaCallbacksCollection::StringResult {
            auto entry = graph.FindModule(entrypoint);
            if (!entry)
                return frontend_resources::LuaCallbacksCollection::Error{"could not find entrypoint"};
            auto view = std::dynamic_pointer_cast<core::view::AbstractViewInterface>(entry);
            if (!view)
                return frontend_resources::LuaCallbacksCollection::Error{"requested entrypoint is not a view"};
            auto camera_samples = view->SampleCameraScenes(camera_path_pattern, num_samples);
            if (camera_samples.empty())
                return frontend_resources::LuaCallbacksCollection::Error{"could not sample camera"};
            return frontend_resources::LuaCallbacksCollection::StringResult{camera_samples};
        }});

    callbacks.add<frontend_resources::LuaCallbacksCollection::StringResult, std::string, std::string, int, bool>(
        "mmProfile", "(string entrypoint, string cameras, unsigned int num_frames, bool pretty)",
        {[&graph, &render_next_frame](std::string entrypoint, std::string cameras, int num_frames,
             bool pretty) -> frontend_resources::LuaCallbacksCollection::StringResult {
            auto entry = graph.FindModule(entrypoint);
            if (!entry)
                return frontend_resources::LuaCallbacksCollection::Error{"could not find entrypoint"};
            auto view = std::dynamic_pointer_cast<core::view::AbstractViewInterface>(entry);
            if (!view)
                return frontend_resources::LuaCallbacksCollection::Error{"requested entrypoint is not a view"};

            auto serializer = core::view::CameraSerializer();
            std::vector<core::view::Camera> cams;
            serializer.deserialize(cams, cameras);

            auto const old_cam = view->GetCamera();

            uint64_t tot_num_frames = num_frames * cams.size();

            auto const tp_start = std::chrono::system_clock::now();
            for (auto const& cam : cams) {
                view->SetCamera(cam);
                for (unsigned int f_idx = 0; f_idx < num_frames; ++f_idx) {
                    render_next_frame();
                }
            }
            auto const tp_end = std::chrono::system_clock::now();

            view->SetCamera(old_cam);

            auto const duration = tp_end - tp_start;

            auto const time_in_ms = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();

            auto const time_per_frame = static_cast<float>(time_in_ms) / static_cast<float>(tot_num_frames);

            std::stringstream sstr;
            if (pretty) {
                sstr << "Total Number of Frames: " << tot_num_frames << "; Elapsed Time (ms): "
                     << std::chrono::duration_cast<std::chrono::milliseconds>(duration).count()
                     << "; Time per Frame (ms): " << time_per_frame;
            } else {
                sstr << tot_num_frames << ", "
                     << std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() << ", "
                     << time_per_frame;
            }

            return frontend_resources::LuaCallbacksCollection::StringResult{sstr.str()};
        }});

    auto& register_callbacks =
        _requestedResourcesReferences[0]
            .getResource<std::function<void(frontend_resources::LuaCallbacksCollection const&)>>();

    register_callbacks(callbacks);
}

} // namespace frontend
} // namespace megamol
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"

class DownloadsApiTest : public ExtensionApiTest {
 public:
  void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    ExtensionApiTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kEnableExperimentalExtensionApis);
  }

  void SetUpTempDownloadsDir() {
    ASSERT_TRUE(tmpdir.CreateUniqueTempDir());
    browser()->profile()->GetPrefs()->SetFilePath(
        prefs::kDownloadDefaultDirectory, tmpdir.path());
  }

 private:
  ScopedTempDir tmpdir;
};

// http://crbug.com/101170
IN_PROC_BROWSER_TEST_F(DownloadsApiTest, FAILS_DownloadsApiTest) {
  SetUpTempDownloadsDir();
  ASSERT_TRUE(StartTestServer());
  ASSERT_TRUE(RunExtensionTest("downloads")) << message_;
}
<commit_msg>Disable DownloadsApiTest BUG=101170<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"

class DownloadsApiTest : public ExtensionApiTest {
 public:
  void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    ExtensionApiTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kEnableExperimentalExtensionApis);
  }

  void SetUpTempDownloadsDir() {
    ASSERT_TRUE(tmpdir.CreateUniqueTempDir());
    browser()->profile()->GetPrefs()->SetFilePath(
        prefs::kDownloadDefaultDirectory, tmpdir.path());
  }

 private:
  ScopedTempDir tmpdir;
};

// http://crbug.com/101170
IN_PROC_BROWSER_TEST_F(DownloadsApiTest, DISABLED_DownloadsApiTest) {
  SetUpTempDownloadsDir();
  ASSERT_TRUE(StartTestServer());
  ASSERT_TRUE(RunExtensionTest("downloads")) << message_;
}
<|endoftext|>


<commit_before>/**
 * @file crc32c.cpp
 * @brief Node.js bindings for CRC-32C calculation using hardware-acceleration, when available.
 *
 * The code below provides the bindings for the node-addon allowing for interfacing of C/C++ code with
 * JavaScript. It chooses between two versions of the CRC-32C calculator:
 * - The hardware-accelerated version that uses Intel's SSE 4.2 instructions, implemented in crc32c_sse42.cpp
 * - A table-lookup based CRC calculated implemented in software for non-Nehalam-based architectures
 *
 * NOTES:
 * - This code, though originally designed for little-endian hardware, should work for all platforms.
 * - Table-based CRC-32C implementation based on code by Mark Adler at http://stackoverflow.com/a/17646775.
 *
 * @author Anand Suresh <anandsuresh@gmail.com>
 */

#include <stdint.h>
#include <napi.h>

#include "crc32c.h"

// Bit-mask for the SSE 4.2 flag in the CPU ID
#define SSE4_2_FLAG         0x100000

// The CRC-32C polynomial in reversed bit order
#define CRC32C_POLYNOMIAL   0x82f63b78

// Stores the CRC-32 lookup table for the software-fallback implementation
static uint32_t crc32cTable[8][256];

/**
 * Cross-platform CPU feature set detection to check for availability of hardware-based CRC-32C
 */
#ifdef _MSC_VER
#include <intrin.h> // __cpuid
#endif
void cpuid(uint32_t op, uint32_t reg[4]) {
#if defined(_MSC_VER)
    __cpuid((int *)reg, 1);
#elif defined(__x86_64__)
    __asm__ volatile(
        "pushq %%rbx       \n\t"
        "cpuid             \n\t"
        "movl  %%ebx, %1   \n\t"
        "popq  %%rbx       \n\t"
        : "=a"(reg[0]), "=r"(reg[1]), "=c"(reg[2]), "=d"(reg[3])
        : "a"(op)
        : "cc");
#elif defined(__i386__)
    __asm__ volatile(
        "pushl %%ebx       \n\t"
        "cpuid             \n\t"
        "movl  %%ebx, %1   \n\t"
        "popl  %%ebx       \n\t"
        : "=a"(reg[0]), "=r"(reg[1]), "=c"(reg[2]), "=d"(reg[3])
        : "a"(op)
        : "cc");
#else
    reg[0] = reg[1] = reg[2] = reg[3] = 0;
#endif
}

/**
 * Returns whether or not Intel's Streaming SIMD Extensions 4.2 is available on the hardware
 *
 * @return true if Intel's Streaming SIMD Extensions 4.2 are present; otherwise false
 */
bool isSSE42Available() {
    uint32_t reg[4];

    cpuid(1, reg);
    return ((reg[2] >> 20) & 1) == 1;
}

/**
 * Initializes the CRC-32C lookup table for software-based CRC calculation
 */
void initCrcTable() {
    uint32_t i, j, crc;

    for (i = 0; i < 256; i++) {
        crc = i;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc32cTable[0][i] = crc;
    }

    for (i = 0; i < 256; i++) {
        crc = crc32cTable[0][i];
        for (j = 1; j < 8; j++) {
            crc = crc32cTable[0][crc & 0xff] ^ (crc >> 8);
            crc32cTable[j][i] = crc;
        }
    }
}

/**
 * Calculates CRC-32C using the lookup table
 *
 * @param initialCrc The initial CRC to use for the operation
 * @param buf The buffer that stores the data whose CRC is to be calculated
 * @param len The size of the buffer
 * @return The CRC-32C of the data in the buffer
 */
uint32_t swCrc32c(uint32_t initialCrc, const char *buf, size_t len) {
    const char *next = buf;
    uint64_t crc = initialCrc;

    // If the string is empty, return 0
    if (len == 0) return (uint32_t)crc;

    // XOR the initial CRC with INT_MAX
    crc ^= 0xFFFFFFFF;

    // Process byte-by-byte until aligned to 8-byte boundary
    while (len && ((uintptr_t) next & 7) != 0) {
        crc = crc32cTable[0][(crc ^ *next++) & 0xff] ^ (crc >> 8);
        len--;
    }

    // Process 8 bytes at a time
    while (len >= 8) {
        crc ^= *(uint64_t *) next;
        crc = crc32cTable[7][(crc >>  0) & 0xff] ^ crc32cTable[6][(crc >>  8) & 0xff]
            ^ crc32cTable[5][(crc >> 16) & 0xff] ^ crc32cTable[4][(crc >> 24) & 0xff]
            ^ crc32cTable[3][(crc >> 32) & 0xff] ^ crc32cTable[2][(crc >> 40) & 0xff]
            ^ crc32cTable[1][(crc >> 48) & 0xff] ^ crc32cTable[0][(crc >> 56)];
        next += 8;
        len -= 8;
    }

    // Process any remaining bytes
    while (len) {
        crc = crc32cTable[0][(crc ^ *next++) & 0xff] ^ (crc >> 8);
        len--;
    }

    // XOR again with INT_MAX
    return (uint32_t)(crc ^= 0xFFFFFFFF);
}

/**
 * Returns whether or not hardware support is available for CRC calculation
 */
Napi::Value isHardwareCrcSupported(const Napi::CallbackInfo& info) {
    Napi::Env env = info.Env();
    return Napi::Boolean::New(env,isSSE42Available());
}

/**
 * Calculates CRC-32C for the specified string/buffer
 */
Napi::Value calculateCrc(const Napi::CallbackInfo& info) {
    Napi::Env env = info.Env();
    uint32_t initCrc;
    uint32_t crc;
    bool useHardwareCrc;

    // Ensure an argument is passed
    if (info.Length() < 1) {
        return Napi::Number::New(env, 0);
    } else if (info.Length() > 3) {
        throw Napi::TypeError::New(env, "Invalid number of arguments!");
    }

    // Check if the table-lookup is required
    if (!info[0].IsBoolean()) {
        throw Napi::TypeError::New(env, "useHardwareCrc isn't a boolean value as expected!");
    }
    useHardwareCrc = info[0].As<Napi::Boolean>();

    // Check for any initial CRC passed to the function
    if (info.Length() > 2) {
        if (!(info[2].IsNumber())) {
            throw Napi::TypeError::New(env, "Initial CRC-32C is not an integer value as expected!");
        }
        initCrc = info[2].As<Napi::Number>().Uint32Value();
    } else {
        initCrc = 0;
    }

    // Ensure the argument is a buffer or a string
    if (info[1].IsBuffer()) {
        Napi::Buffer<char> buf = info[1].As<Napi::Buffer<char>>();
        if (useHardwareCrc) {
            crc = hwCrc32c(initCrc, (const char *)buf.Data(), (size_t)buf.Length());
        } else {
            crc = swCrc32c(initCrc, (const char *)buf.Data(), (size_t)buf.Length());
        }
    } else if (info[1].IsObject()) {
        throw Napi::TypeError::New(env, "Cannot compute CRC-32C for objects!");
    } else {
        std::string strInput = info[1].As<Napi::String>().Utf8Value();

        /*if (useHardwareCrc) {
            crc = hwCrc32c(initCrc, (const char *)(*strInput.Utf8Value()), (size_t)strInput.Utf8Length());
        } else {
            crc = swCrc32c(initCrc, (const char *)(*strInput.Utf8Value()), (size_t)strInput.Utf8Length());
        }*/
    }

    // Calculate the 32-bit CRC
    return Napi::Number::New(env, crc);
}

/**
 * Initialize the module
 */
Napi::Object init(Napi::Env env, Napi::Object exports) {
    initCrcTable();
    exports["isHardwareCrcSupported"] = Napi::Function::New(env, isHardwareCrcSupported);
    exports["calculateCrc"] = Napi::Function::New(env, calculateCrc);
    return exports;
};

NODE_API_MODULE(sse4_crc32, init);
<commit_msg>End preliminary work on porting to N-API<commit_after>/**
 * @file crc32c.cpp
 * @brief Node.js bindings for CRC-32C calculation using hardware-acceleration, when available.
 *
 * The code below provides the bindings for the node-addon allowing for interfacing of C/C++ code with
 * JavaScript. It chooses between two versions of the CRC-32C calculator:
 * - The hardware-accelerated version that uses Intel's SSE 4.2 instructions, implemented in crc32c_sse42.cpp
 * - A table-lookup based CRC calculated implemented in software for non-Nehalam-based architectures
 *
 * NOTES:
 * - This code, though originally designed for little-endian hardware, should work for all platforms.
 * - Table-based CRC-32C implementation based on code by Mark Adler at http://stackoverflow.com/a/17646775.
 *
 * @author Anand Suresh <anandsuresh@gmail.com>
 */

#include <stdint.h>
#include <napi.h>

#include "crc32c.h"

// Bit-mask for the SSE 4.2 flag in the CPU ID
#define SSE4_2_FLAG         0x100000

// The CRC-32C polynomial in reversed bit order
#define CRC32C_POLYNOMIAL   0x82f63b78

// Stores the CRC-32 lookup table for the software-fallback implementation
static uint32_t crc32cTable[8][256];

/**
 * Cross-platform CPU feature set detection to check for availability of hardware-based CRC-32C
 */
#ifdef _MSC_VER
#include <intrin.h> // __cpuid
#endif
void cpuid(uint32_t op, uint32_t reg[4]) {
#if defined(_MSC_VER)
    __cpuid((int *)reg, 1);
#elif defined(__x86_64__)
    __asm__ volatile(
        "pushq %%rbx       \n\t"
        "cpuid             \n\t"
        "movl  %%ebx, %1   \n\t"
        "popq  %%rbx       \n\t"
        : "=a"(reg[0]), "=r"(reg[1]), "=c"(reg[2]), "=d"(reg[3])
        : "a"(op)
        : "cc");
#elif defined(__i386__)
    __asm__ volatile(
        "pushl %%ebx       \n\t"
        "cpuid             \n\t"
        "movl  %%ebx, %1   \n\t"
        "popl  %%ebx       \n\t"
        : "=a"(reg[0]), "=r"(reg[1]), "=c"(reg[2]), "=d"(reg[3])
        : "a"(op)
        : "cc");
#else
    reg[0] = reg[1] = reg[2] = reg[3] = 0;
#endif
}

/**
 * Returns whether or not Intel's Streaming SIMD Extensions 4.2 is available on the hardware
 *
 * @return true if Intel's Streaming SIMD Extensions 4.2 are present; otherwise false
 */
bool isSSE42Available() {
    uint32_t reg[4];

    cpuid(1, reg);
    return ((reg[2] >> 20) & 1) == 1;
}

/**
 * Initializes the CRC-32C lookup table for software-based CRC calculation
 */
void initCrcTable() {
    uint32_t i, j, crc;

    for (i = 0; i < 256; i++) {
        crc = i;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc32cTable[0][i] = crc;
    }

    for (i = 0; i < 256; i++) {
        crc = crc32cTable[0][i];
        for (j = 1; j < 8; j++) {
            crc = crc32cTable[0][crc & 0xff] ^ (crc >> 8);
            crc32cTable[j][i] = crc;
        }
    }
}

/**
 * Calculates CRC-32C using the lookup table
 *
 * @param initialCrc The initial CRC to use for the operation
 * @param buf The buffer that stores the data whose CRC is to be calculated
 * @param len The size of the buffer
 * @return The CRC-32C of the data in the buffer
 */
uint32_t swCrc32c(uint32_t initialCrc, const char *buf, size_t len) {
    const char *next = buf;
    uint64_t crc = initialCrc;

    // If the string is empty, return 0
    if (len == 0) return (uint32_t)crc;

    // XOR the initial CRC with INT_MAX
    crc ^= 0xFFFFFFFF;

    // Process byte-by-byte until aligned to 8-byte boundary
    while (len && ((uintptr_t) next & 7) != 0) {
        crc = crc32cTable[0][(crc ^ *next++) & 0xff] ^ (crc >> 8);
        len--;
    }

    // Process 8 bytes at a time
    while (len >= 8) {
        crc ^= *(uint64_t *) next;
        crc = crc32cTable[7][(crc >>  0) & 0xff] ^ crc32cTable[6][(crc >>  8) & 0xff]
            ^ crc32cTable[5][(crc >> 16) & 0xff] ^ crc32cTable[4][(crc >> 24) & 0xff]
            ^ crc32cTable[3][(crc >> 32) & 0xff] ^ crc32cTable[2][(crc >> 40) & 0xff]
            ^ crc32cTable[1][(crc >> 48) & 0xff] ^ crc32cTable[0][(crc >> 56)];
        next += 8;
        len -= 8;
    }

    // Process any remaining bytes
    while (len) {
        crc = crc32cTable[0][(crc ^ *next++) & 0xff] ^ (crc >> 8);
        len--;
    }

    // XOR again with INT_MAX
    return (uint32_t)(crc ^= 0xFFFFFFFF);
}

/**
 * Returns whether or not hardware support is available for CRC calculation
 */
Napi::Value isHardwareCrcSupported(const Napi::CallbackInfo& info) {
    Napi::Env env = info.Env();
    return Napi::Boolean::New(env,isSSE42Available());
}

/**
 * Calculates CRC-32C for the specified string/buffer
 */
Napi::Value calculateCrc(const Napi::CallbackInfo& info) {
    Napi::Env env = info.Env();
    uint32_t initCrc;
    uint32_t crc;
    bool useHardwareCrc;

    // Ensure an argument is passed
    if (info.Length() < 1) {
        return Napi::Number::New(env, 0);
    } else if (info.Length() > 3) {
        throw Napi::TypeError::New(env, "Invalid number of arguments!");
    }

    // Check if the table-lookup is required
    if (!info[0].IsBoolean()) {
        throw Napi::TypeError::New(env, "useHardwareCrc isn't a boolean value as expected!");
    }
    useHardwareCrc = info[0].As<Napi::Boolean>();

    // Check for any initial CRC passed to the function
    if (info.Length() > 2) {
        if (!(info[2].IsNumber())) {
            throw Napi::TypeError::New(env, "Initial CRC-32C is not an integer value as expected!");
        }
        initCrc = info[2].As<Napi::Number>().Uint32Value();
    } else {
        initCrc = 0;
    }

    // Ensure the argument is a buffer or a string
    if (info[1].IsBuffer()) {
        Napi::Buffer<char> buf = info[1].As<Napi::Buffer<char>>();
        if (useHardwareCrc) {
            crc = hwCrc32c(initCrc, (const char *)buf.Data(), (size_t)buf.Length());
        } else {
            crc = swCrc32c(initCrc, (const char *)buf.Data(), (size_t)buf.Length());
        }
    } else if (info[1].IsObject()) {
        throw Napi::TypeError::New(env, "Cannot compute CRC-32C for objects!");
    } else {
        std::string strInput = info[1].As<Napi::String>().Utf8Value();

        if (useHardwareCrc) {
            crc = hwCrc32c(initCrc, (const char *)strInput.c_str(), (size_t)strInput.length());
        } else {
            crc = swCrc32c(initCrc, (const char *)strInput.c_str(), (size_t)strInput.length());
        }
    }

    // Calculate the 32-bit CRC
    return Napi::Number::New(env, crc);
}

/**
 * Initialize the module
 */
Napi::Object init(Napi::Env env, Napi::Object exports) {
    initCrcTable();
    exports["isHardwareCrcSupported"] = Napi::Function::New(env, isHardwareCrcSupported);
    exports["calculateCrc"] = Napi::Function::New(env, calculateCrc);
    return exports;
};

NODE_API_MODULE(sse4_crc32, init);
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: passcrtdlg.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: obo $ $Date: 2005-03-15 11:44:53 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _SVT_FILEDLG_HXX
#include <svtools/filedlg.hxx>
#endif
#ifndef _SV_MSGBOX_HXX
#include <vcl/msgbox.hxx>
#endif

#ifndef UUI_IDS_HRC
#include <ids.hrc>
#endif
#ifndef UUI_PASSCRTDLG_HRC
#include <passcrtdlg.hrc>
#endif
#ifndef UUI_PASSCRTDLG_HXX
#include <passcrtdlg.hxx>
#endif

// PasswordCreateDialog---------------------------------------------------

// -----------------------------------------------------------------------

IMPL_LINK( PasswordCreateDialog, EditHdl_Impl, Edit *, EMPTYARG )
{
    aOKBtn.Enable( aEDPasswordCrt.GetText().Len() >= nMinLen );
    return 0;
}

// -----------------------------------------------------------------------

IMPL_LINK( PasswordCreateDialog, OKHdl_Impl, OKButton *, EMPTYARG )
{
    // compare both passwords and show message box if there are not equal!!
    if( aEDPasswordCrt.GetText() == aEDPasswordRepeat.GetText() )
        EndDialog( RET_OK );
    else
    {
        String aErrorMsg( ResId( STR_ERROR_PASSWORDS_NOT_IDENTICAL, pResourceMgr ));
        ErrorBox aErrorBox( this, WB_OK, aErrorMsg );
        aErrorBox.Execute();
        aEDPasswordCrt.SetText( String() );
        aEDPasswordRepeat.SetText( String() );
        aEDPasswordCrt.GrabFocus();
    }
    return 1;
}

// -----------------------------------------------------------------------

PasswordCreateDialog::PasswordCreateDialog
(
    Window*                                     pParent,
    ResMgr*                                     pResMgr
) :

    ModalDialog( pParent, ResId( DLG_UUI_PASSWORD_CRT, pResMgr ) ),

    aFTPasswordCrt      ( this, ResId( FT_PASSWORD_CRT ) ),
    aEDPasswordCrt      ( this, ResId( ED_PASSWORD_CRT ) ),
    aFTPasswordRepeat   ( this, ResId( FT_PASSWORD_REPEAT ) ),
    aEDPasswordRepeat   ( this, ResId( ED_PASSWORD_REPEAT ) ),
    aOKBtn                  ( this, ResId( BTN_PASSCRT_OK ) ),
    aCancelBtn              ( this, ResId( BTN_PASSCRT_CANCEL ) ),
    aHelpBtn                ( this, ResId( BTN_PASSCRT_HELP ) ),
    pResourceMgr            ( pResMgr ),
    nMinLen(5)
{
    FreeResource();

    aOKBtn.SetClickHdl( LINK( this, PasswordCreateDialog, OKHdl_Impl ) );
    aEDPasswordCrt.SetModifyHdl( LINK( this, PasswordCreateDialog, EditHdl_Impl ) );

    aOKBtn.Enable( sal_False );
};

<commit_msg>INTEGRATION: CWS ooo19126 (1.3.26); FILE MERGED 2005/09/05 17:09:49 rt 1.3.26.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: passcrtdlg.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 10:25:25 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _SVT_FILEDLG_HXX
#include <svtools/filedlg.hxx>
#endif
#ifndef _SV_MSGBOX_HXX
#include <vcl/msgbox.hxx>
#endif

#ifndef UUI_IDS_HRC
#include <ids.hrc>
#endif
#ifndef UUI_PASSCRTDLG_HRC
#include <passcrtdlg.hrc>
#endif
#ifndef UUI_PASSCRTDLG_HXX
#include <passcrtdlg.hxx>
#endif

// PasswordCreateDialog---------------------------------------------------

// -----------------------------------------------------------------------

IMPL_LINK( PasswordCreateDialog, EditHdl_Impl, Edit *, EMPTYARG )
{
    aOKBtn.Enable( aEDPasswordCrt.GetText().Len() >= nMinLen );
    return 0;
}

// -----------------------------------------------------------------------

IMPL_LINK( PasswordCreateDialog, OKHdl_Impl, OKButton *, EMPTYARG )
{
    // compare both passwords and show message box if there are not equal!!
    if( aEDPasswordCrt.GetText() == aEDPasswordRepeat.GetText() )
        EndDialog( RET_OK );
    else
    {
        String aErrorMsg( ResId( STR_ERROR_PASSWORDS_NOT_IDENTICAL, pResourceMgr ));
        ErrorBox aErrorBox( this, WB_OK, aErrorMsg );
        aErrorBox.Execute();
        aEDPasswordCrt.SetText( String() );
        aEDPasswordRepeat.SetText( String() );
        aEDPasswordCrt.GrabFocus();
    }
    return 1;
}

// -----------------------------------------------------------------------

PasswordCreateDialog::PasswordCreateDialog
(
    Window*                                     pParent,
    ResMgr*                                     pResMgr
) :

    ModalDialog( pParent, ResId( DLG_UUI_PASSWORD_CRT, pResMgr ) ),

    aFTPasswordCrt      ( this, ResId( FT_PASSWORD_CRT ) ),
    aEDPasswordCrt      ( this, ResId( ED_PASSWORD_CRT ) ),
    aFTPasswordRepeat   ( this, ResId( FT_PASSWORD_REPEAT ) ),
    aEDPasswordRepeat   ( this, ResId( ED_PASSWORD_REPEAT ) ),
    aOKBtn                  ( this, ResId( BTN_PASSCRT_OK ) ),
    aCancelBtn              ( this, ResId( BTN_PASSCRT_CANCEL ) ),
    aHelpBtn                ( this, ResId( BTN_PASSCRT_HELP ) ),
    pResourceMgr            ( pResMgr ),
    nMinLen(5)
{
    FreeResource();

    aOKBtn.SetClickHdl( LINK( this, PasswordCreateDialog, OKHdl_Impl ) );
    aEDPasswordCrt.SetModifyHdl( LINK( this, PasswordCreateDialog, EditHdl_Impl ) );

    aOKBtn.Enable( sal_False );
};

<|endoftext|>


<commit_before>// Copyright 2018 The clvk 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 "device.hpp"
#include "memory.hpp"
#include "utils.hpp"

cvk_device* cvk_device::create(VkPhysicalDevice pdev) {
    cvk_device* device = new cvk_device(pdev);

    if (!device->init()) {
        delete device;
        return nullptr;
    }

    return device;
}

bool cvk_device::init_queues(uint32_t* num_queues, uint32_t* queue_family) {
    // Get number of queue families
    uint32_t num_families;
    vkGetPhysicalDeviceQueueFamilyProperties(m_pdev, &num_families, nullptr);

    cvk_info_fn(
        "physical device (%s) has %u queue families:",
        vulkan_physical_device_type_string(m_properties.deviceType).c_str(),
        num_families);

    // Get their properties
    std::vector<VkQueueFamilyProperties> families(num_families);
    vkGetPhysicalDeviceQueueFamilyProperties(m_pdev, &num_families,
                                             families.data());

    // Look for suitable queues
    bool found_queues = false;
    *num_queues = 0;
    for (uint32_t i = 0; i < num_families; i++) {

        cvk_info_fn("queue family %u: %2u queues | %s", i,
                    families[i].queueCount,
                    vulkan_queue_flags_string(families[i].queueFlags).c_str());

        if (!found_queues && (families[i].queueFlags & VK_QUEUE_COMPUTE_BIT)) {
            *queue_family = i;
            *num_queues = families[i].queueCount;
            found_queues = true;
        }
    }

    if (!found_queues) {
        cvk_error("Could not find a suitable queue family for this device");
        return false;
    }

    // Initialise the queue allocator
    m_vulkan_queue_alloc_index = 0;

    return true;
}

bool cvk_device::init_extensions() {
    uint32_t numext;
    VkResult res =
        vkEnumerateDeviceExtensionProperties(m_pdev, nullptr, &numext, nullptr);
    CVK_VK_CHECK_ERROR_RET(
        res, false, "Failed to get the number of device extension properties");

    cvk_info("%u device extension properties reported.", numext);

    std::vector<VkExtensionProperties> extensions(numext);
    res = vkEnumerateDeviceExtensionProperties(m_pdev, nullptr, &numext,
                                               extensions.data());
    CVK_VK_CHECK_ERROR_RET(res, false,
                           "Could not enumerate device extension properties");

    if (m_properties.apiVersion < VK_MAKE_VERSION(1, 1, 0)) {
        m_vulkan_device_extensions.push_back(
            VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME);
        m_vulkan_device_extensions.push_back(
            VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
    }

    const std::vector<const char*> desired_extensions = {
        VK_KHR_16BIT_STORAGE_EXTENSION_NAME,
        VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME,
        VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME,
    };

    for (size_t i = 0; i < numext; i++) {
        cvk_info("Found extension %s, spec version %u",
                 extensions[i].extensionName, extensions[i].specVersion);

        for (auto de : desired_extensions) {
            if (!strcmp(de, extensions[i].extensionName)) {
                m_vulkan_device_extensions.push_back(de);
                cvk_info_fn("found extension %s, enabling", de);
            }
        }
    }

    return true;
}

void cvk_device::init_features() {
    // Query supported features.
    m_features_float16_int8.sType =
        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR;
    m_features_float16_int8.pNext = nullptr;

    m_features_variable_pointer.sType =
        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES;
    m_features_variable_pointer.pNext = &m_features_float16_int8;

    VkPhysicalDeviceFeatures2 supported_features;
    supported_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
    supported_features.pNext = &m_features_variable_pointer;

    vkGetPhysicalDeviceFeatures2(m_pdev, &supported_features);

    // Selectively enable core features.
    memset(&m_features, 0, sizeof(m_features));

    if (supported_features.features.shaderInt16) {
        m_features.features.shaderInt16 = VK_TRUE;
    }
    if (supported_features.features.shaderInt64) {
        m_features.features.shaderInt64 = VK_TRUE;
    }
    if (supported_features.features.shaderFloat64) {
        m_features.features.shaderFloat64 = VK_TRUE;
    }
    if (supported_features.features.shaderStorageImageWriteWithoutFormat) {
        m_features.features.shaderStorageImageWriteWithoutFormat = VK_TRUE;
    }

    // All queried extended features are enabled when supported.
    m_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
    m_features.pNext = &m_features_variable_pointer;
}

void cvk_device::construct_extension_string() {

    // Start with required extensions
    m_extensions = "cl_khr_global_int32_base_atomics "
                   "cl_khr_global_int32_extended_atomics "
                   "cl_khr_local_int32_base_atomics "
                   "cl_khr_local_int32_extended_atomics "
                   "cl_khr_byte_addressable_store ";

    // Add always supported extension
    m_extensions += "cl_khr_il_program ";
}

bool cvk_device::create_vulkan_queues_and_device(uint32_t num_queues,
                                                 uint32_t queue_family) {
    // Give all queues the same priority
    std::vector<float> queuePriorities(num_queues, 1.0f);

    VkDeviceQueueCreateInfo queueCreateInfo = {
        VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
        nullptr,
        0, // flags
        queue_family,
        num_queues, // queueCount
        queuePriorities.data()};

    // Create logical device
    const VkDeviceCreateInfo createInfo = {
        VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType
        &m_features,                          // pNext
        0,                                    // flags
        1,                                    // queueCreateInfoCount
        &queueCreateInfo,                     // pQueueCreateInfos,
        0,                                    // enabledLayerCount
        nullptr,                              // ppEnabledLayerNames
        static_cast<uint32_t>(
            m_vulkan_device_extensions.size()), // enabledExtensionCount
        m_vulkan_device_extensions.data(),      // ppEnabledExtensionNames
        nullptr,                                // pEnabledFeatures
    };

    VkResult res = vkCreateDevice(m_pdev, &createInfo, nullptr, &m_dev);
    CVK_VK_CHECK_ERROR_RET(res, false, "Failed to create a device");

    // Construct the queue wrappers now that our queues exist
    for (auto i = 0U; i < num_queues; i++) {
        VkQueue queue;

        vkGetDeviceQueue(m_dev, queue_family, i, &queue);
        m_vulkan_queues.emplace_back(
            cvk_vulkan_queue_wrapper(queue, queue_family));
    }

    return true;
}

bool cvk_device::compute_buffer_alignement_requirements() {
    // Work out the required alignment for buffers
    const VkBufferCreateInfo bufferCreateInfo = {
        VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // sType
        nullptr,                              // pNext
        0,                                    // flags
        1,                                    // size
        cvk_buffer::USAGE_FLAGS,              // usage
        VK_SHARING_MODE_EXCLUSIVE,
        0,       // queueFamilyIndexCount
        nullptr, // pQueueFamilyIndices
    };

    VkBuffer buffer;
    auto res = vkCreateBuffer(m_dev, &bufferCreateInfo, nullptr, &buffer);
    CVK_VK_CHECK_ERROR_RET(res, false, "Failed to create a buffer");

    VkMemoryRequirements memreqs;
    vkGetBufferMemoryRequirements(m_dev, buffer, &memreqs);

    uint32_t alignment_bits = memreqs.alignment * 8;
    // The OpenCL spec requires at least 1024 bits (long16's alignment)
    m_mem_base_addr_align = std::max(alignment_bits, 1024u);
    vkDestroyBuffer(m_dev, buffer, nullptr);

    return true;
}

void cvk_device::log_limits_and_memory_information() {
    // Print relevant device limits
    const VkPhysicalDeviceLimits& limits = vulkan_limits();
    cvk_info_fn("device's resources per stage limits:");
    cvk_info_fn("    total = %u", limits.maxPerStageResources);
    cvk_info_fn("    uniform buffers = %u",
                limits.maxPerStageDescriptorUniformBuffers);
    cvk_info_fn("    storage buffers = %u",
                limits.maxPerStageDescriptorStorageBuffers);
    cvk_info_fn("device's max buffer size = %s",
                pretty_size(limits.maxStorageBufferRange).c_str());

    // Print memoy information
    cvk_info_fn("device has %u memory types:",
                m_mem_properties.memoryTypeCount);
    for (uint32_t i = 0; i < m_mem_properties.memoryTypeCount; i++) {
        VkMemoryType memtype = m_mem_properties.memoryTypes[i];
        auto heapsize = m_mem_properties.memoryHeaps[memtype.heapIndex].size;
        cvk_info_fn(
            "    %u: heap = %u, %s | %s", i, memtype.heapIndex,
            pretty_size(heapsize).c_str(),
            vulkan_memory_property_flags_string(memtype.propertyFlags).c_str());
    }

    cvk_info_fn("device has %u memory heaps:",
                m_mem_properties.memoryHeapCount);
    for (uint32_t i = 0; i < m_mem_properties.memoryHeapCount; i++) {
        VkMemoryHeap memheap = m_mem_properties.memoryHeaps[i];
        cvk_info_fn("    %u: %s | %s", i, pretty_size(memheap.size).c_str(),
                    vulkan_memory_property_flags_string(memheap.flags).c_str());
    }
}

bool cvk_device::init() {
    cvk_info_fn("Initialising device %s", m_properties.deviceName);

    uint32_t num_queues, queue_family;
    if (!init_queues(&num_queues, &queue_family)) {
        return false;
    }

    if (!init_extensions()) {
        return false;
    }

    init_features();

    construct_extension_string();

    if (!create_vulkan_queues_and_device(num_queues, queue_family)) {
        return false;
    }

    if (!compute_buffer_alignement_requirements()) {
        return false;
    }

    log_limits_and_memory_information();

    return true;
}

bool cvk_device::supports_capability(spv::Capability capability) const {
    switch (capability) {
    // Capabilities required by all Vulkan implementations:
    case spv::CapabilityShader:
    case spv::CapabilitySampled1D:
    case spv::CapabilityImage1D:
    case spv::CapabilityImageQuery:
        return true;
    // Optional capabilities:
    case spv::CapabilityFloat16:
        return m_features_float16_int8.shaderFloat16;
    case spv::CapabilityFloat64:
        return m_features.features.shaderFloat64;
    case spv::CapabilityInt8:
        return m_features_float16_int8.shaderInt8;
    case spv::CapabilityInt16:
        return m_features.features.shaderInt16;
    case spv::CapabilityInt64:
        return m_features.features.shaderInt64;
    case spv::CapabilityStorageImageWriteWithoutFormat:
        return m_features.features.shaderStorageImageWriteWithoutFormat;
    case spv::CapabilityVariablePointers:
        return m_features_variable_pointer.variablePointers;
    case spv::CapabilityVariablePointersStorageBuffer:
        return m_features_variable_pointer.variablePointersStorageBuffer;
    // Capabilities that have not yet been mapped to Vulkan features:
    default:
        cvk_warn_fn("Capability %d not yet mapped to a feature.", capability);
        return false;
    }
}
<commit_msg>Don't report cl_khr_il_program when using clspv online building<commit_after>// Copyright 2018 The clvk 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 "device.hpp"
#include "memory.hpp"
#include "utils.hpp"

cvk_device* cvk_device::create(VkPhysicalDevice pdev) {
    cvk_device* device = new cvk_device(pdev);

    if (!device->init()) {
        delete device;
        return nullptr;
    }

    return device;
}

bool cvk_device::init_queues(uint32_t* num_queues, uint32_t* queue_family) {
    // Get number of queue families
    uint32_t num_families;
    vkGetPhysicalDeviceQueueFamilyProperties(m_pdev, &num_families, nullptr);

    cvk_info_fn(
        "physical device (%s) has %u queue families:",
        vulkan_physical_device_type_string(m_properties.deviceType).c_str(),
        num_families);

    // Get their properties
    std::vector<VkQueueFamilyProperties> families(num_families);
    vkGetPhysicalDeviceQueueFamilyProperties(m_pdev, &num_families,
                                             families.data());

    // Look for suitable queues
    bool found_queues = false;
    *num_queues = 0;
    for (uint32_t i = 0; i < num_families; i++) {

        cvk_info_fn("queue family %u: %2u queues | %s", i,
                    families[i].queueCount,
                    vulkan_queue_flags_string(families[i].queueFlags).c_str());

        if (!found_queues && (families[i].queueFlags & VK_QUEUE_COMPUTE_BIT)) {
            *queue_family = i;
            *num_queues = families[i].queueCount;
            found_queues = true;
        }
    }

    if (!found_queues) {
        cvk_error("Could not find a suitable queue family for this device");
        return false;
    }

    // Initialise the queue allocator
    m_vulkan_queue_alloc_index = 0;

    return true;
}

bool cvk_device::init_extensions() {
    uint32_t numext;
    VkResult res =
        vkEnumerateDeviceExtensionProperties(m_pdev, nullptr, &numext, nullptr);
    CVK_VK_CHECK_ERROR_RET(
        res, false, "Failed to get the number of device extension properties");

    cvk_info("%u device extension properties reported.", numext);

    std::vector<VkExtensionProperties> extensions(numext);
    res = vkEnumerateDeviceExtensionProperties(m_pdev, nullptr, &numext,
                                               extensions.data());
    CVK_VK_CHECK_ERROR_RET(res, false,
                           "Could not enumerate device extension properties");

    if (m_properties.apiVersion < VK_MAKE_VERSION(1, 1, 0)) {
        m_vulkan_device_extensions.push_back(
            VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME);
        m_vulkan_device_extensions.push_back(
            VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
    }

    const std::vector<const char*> desired_extensions = {
        VK_KHR_16BIT_STORAGE_EXTENSION_NAME,
        VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME,
        VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME,
    };

    for (size_t i = 0; i < numext; i++) {
        cvk_info("Found extension %s, spec version %u",
                 extensions[i].extensionName, extensions[i].specVersion);

        for (auto de : desired_extensions) {
            if (!strcmp(de, extensions[i].extensionName)) {
                m_vulkan_device_extensions.push_back(de);
                cvk_info_fn("found extension %s, enabling", de);
            }
        }
    }

    return true;
}

void cvk_device::init_features() {
    // Query supported features.
    m_features_float16_int8.sType =
        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR;
    m_features_float16_int8.pNext = nullptr;

    m_features_variable_pointer.sType =
        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES;
    m_features_variable_pointer.pNext = &m_features_float16_int8;

    VkPhysicalDeviceFeatures2 supported_features;
    supported_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
    supported_features.pNext = &m_features_variable_pointer;

    vkGetPhysicalDeviceFeatures2(m_pdev, &supported_features);

    // Selectively enable core features.
    memset(&m_features, 0, sizeof(m_features));

    if (supported_features.features.shaderInt16) {
        m_features.features.shaderInt16 = VK_TRUE;
    }
    if (supported_features.features.shaderInt64) {
        m_features.features.shaderInt64 = VK_TRUE;
    }
    if (supported_features.features.shaderFloat64) {
        m_features.features.shaderFloat64 = VK_TRUE;
    }
    if (supported_features.features.shaderStorageImageWriteWithoutFormat) {
        m_features.features.shaderStorageImageWriteWithoutFormat = VK_TRUE;
    }

    // All queried extended features are enabled when supported.
    m_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
    m_features.pNext = &m_features_variable_pointer;
}

void cvk_device::construct_extension_string() {

    // Start with required extensions
    m_extensions = "cl_khr_global_int32_base_atomics "
                   "cl_khr_global_int32_extended_atomics "
                   "cl_khr_local_int32_base_atomics "
                   "cl_khr_local_int32_extended_atomics "
                   "cl_khr_byte_addressable_store ";

    // Add always supported extension
#ifndef CLSPV_ONLINE_COMPILER
    m_extensions += "cl_khr_il_program ";
#endif
}

bool cvk_device::create_vulkan_queues_and_device(uint32_t num_queues,
                                                 uint32_t queue_family) {
    // Give all queues the same priority
    std::vector<float> queuePriorities(num_queues, 1.0f);

    VkDeviceQueueCreateInfo queueCreateInfo = {
        VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
        nullptr,
        0, // flags
        queue_family,
        num_queues, // queueCount
        queuePriorities.data()};

    // Create logical device
    const VkDeviceCreateInfo createInfo = {
        VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType
        &m_features,                          // pNext
        0,                                    // flags
        1,                                    // queueCreateInfoCount
        &queueCreateInfo,                     // pQueueCreateInfos,
        0,                                    // enabledLayerCount
        nullptr,                              // ppEnabledLayerNames
        static_cast<uint32_t>(
            m_vulkan_device_extensions.size()), // enabledExtensionCount
        m_vulkan_device_extensions.data(),      // ppEnabledExtensionNames
        nullptr,                                // pEnabledFeatures
    };

    VkResult res = vkCreateDevice(m_pdev, &createInfo, nullptr, &m_dev);
    CVK_VK_CHECK_ERROR_RET(res, false, "Failed to create a device");

    // Construct the queue wrappers now that our queues exist
    for (auto i = 0U; i < num_queues; i++) {
        VkQueue queue;

        vkGetDeviceQueue(m_dev, queue_family, i, &queue);
        m_vulkan_queues.emplace_back(
            cvk_vulkan_queue_wrapper(queue, queue_family));
    }

    return true;
}

bool cvk_device::compute_buffer_alignement_requirements() {
    // Work out the required alignment for buffers
    const VkBufferCreateInfo bufferCreateInfo = {
        VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // sType
        nullptr,                              // pNext
        0,                                    // flags
        1,                                    // size
        cvk_buffer::USAGE_FLAGS,              // usage
        VK_SHARING_MODE_EXCLUSIVE,
        0,       // queueFamilyIndexCount
        nullptr, // pQueueFamilyIndices
    };

    VkBuffer buffer;
    auto res = vkCreateBuffer(m_dev, &bufferCreateInfo, nullptr, &buffer);
    CVK_VK_CHECK_ERROR_RET(res, false, "Failed to create a buffer");

    VkMemoryRequirements memreqs;
    vkGetBufferMemoryRequirements(m_dev, buffer, &memreqs);

    uint32_t alignment_bits = memreqs.alignment * 8;
    // The OpenCL spec requires at least 1024 bits (long16's alignment)
    m_mem_base_addr_align = std::max(alignment_bits, 1024u);
    vkDestroyBuffer(m_dev, buffer, nullptr);

    return true;
}

void cvk_device::log_limits_and_memory_information() {
    // Print relevant device limits
    const VkPhysicalDeviceLimits& limits = vulkan_limits();
    cvk_info_fn("device's resources per stage limits:");
    cvk_info_fn("    total = %u", limits.maxPerStageResources);
    cvk_info_fn("    uniform buffers = %u",
                limits.maxPerStageDescriptorUniformBuffers);
    cvk_info_fn("    storage buffers = %u",
                limits.maxPerStageDescriptorStorageBuffers);
    cvk_info_fn("device's max buffer size = %s",
                pretty_size(limits.maxStorageBufferRange).c_str());

    // Print memoy information
    cvk_info_fn("device has %u memory types:",
                m_mem_properties.memoryTypeCount);
    for (uint32_t i = 0; i < m_mem_properties.memoryTypeCount; i++) {
        VkMemoryType memtype = m_mem_properties.memoryTypes[i];
        auto heapsize = m_mem_properties.memoryHeaps[memtype.heapIndex].size;
        cvk_info_fn(
            "    %u: heap = %u, %s | %s", i, memtype.heapIndex,
            pretty_size(heapsize).c_str(),
            vulkan_memory_property_flags_string(memtype.propertyFlags).c_str());
    }

    cvk_info_fn("device has %u memory heaps:",
                m_mem_properties.memoryHeapCount);
    for (uint32_t i = 0; i < m_mem_properties.memoryHeapCount; i++) {
        VkMemoryHeap memheap = m_mem_properties.memoryHeaps[i];
        cvk_info_fn("    %u: %s | %s", i, pretty_size(memheap.size).c_str(),
                    vulkan_memory_property_flags_string(memheap.flags).c_str());
    }
}

bool cvk_device::init() {
    cvk_info_fn("Initialising device %s", m_properties.deviceName);

    uint32_t num_queues, queue_family;
    if (!init_queues(&num_queues, &queue_family)) {
        return false;
    }

    if (!init_extensions()) {
        return false;
    }

    init_features();

    construct_extension_string();

    if (!create_vulkan_queues_and_device(num_queues, queue_family)) {
        return false;
    }

    if (!compute_buffer_alignement_requirements()) {
        return false;
    }

    log_limits_and_memory_information();

    return true;
}

bool cvk_device::supports_capability(spv::Capability capability) const {
    switch (capability) {
    // Capabilities required by all Vulkan implementations:
    case spv::CapabilityShader:
    case spv::CapabilitySampled1D:
    case spv::CapabilityImage1D:
    case spv::CapabilityImageQuery:
        return true;
    // Optional capabilities:
    case spv::CapabilityFloat16:
        return m_features_float16_int8.shaderFloat16;
    case spv::CapabilityFloat64:
        return m_features.features.shaderFloat64;
    case spv::CapabilityInt8:
        return m_features_float16_int8.shaderInt8;
    case spv::CapabilityInt16:
        return m_features.features.shaderInt16;
    case spv::CapabilityInt64:
        return m_features.features.shaderInt64;
    case spv::CapabilityStorageImageWriteWithoutFormat:
        return m_features.features.shaderStorageImageWriteWithoutFormat;
    case spv::CapabilityVariablePointers:
        return m_features_variable_pointer.variablePointers;
    case spv::CapabilityVariablePointersStorageBuffer:
        return m_features_variable_pointer.variablePointersStorageBuffer;
    // Capabilities that have not yet been mapped to Vulkan features:
    default:
        cvk_warn_fn("Capability %d not yet mapped to a feature.", capability);
        return false;
    }
}
<|endoftext|>


<commit_before>#include "df_bmp.h"

#include "df_bitmap.h"

#include <memory.h>
#include <stdint.h>
#include <stdio.h>

#define BMP_RGB				0
#define OS2INFOHEADERSIZE  12
#define WININFOHEADERSIZE  40

struct BitmapFileHeader
{
	uint16_t type;
	uint32_t size;
	uint16_t reserved1;
	uint16_t reserved2;
	uint32_t offBits;
};

struct BitmapInfoHeader
{
	uint32_t width;
	uint32_t height;
	uint16_t bitCount;
	uint32_t compression;
};

struct WinBmpInfoHeader
{
	uint32_t width;
	uint32_t height;
	uint16_t planes;
	uint16_t bitCount;
	uint32_t compression;
	uint32_t sizeImage;
	uint32_t xPelsPerMeter;
	uint32_t biYPelsPerMeter;
	uint32_t biClrUsed;
	uint32_t biClrImportant;
};

// ****************************************************************************
// Private Functions
// ****************************************************************************

static uint8_t ReadU8(FILE *file)
{
    return fgetc(file);
}

static short ReadS16(FILE *file)
{
    int b1 = fgetc(file);
    int b2 = fgetc(file);
    return ((b2 << 8) | b1);
}

static int ReadS32(FILE *file)
{
    int b1 = fgetc(file);
    int b2 = fgetc(file);
    int b3 = fgetc(file);
    int b4 = fgetc(file);
    return ((b4 << 24) | (b3 << 16) | (b2 << 8) | b1);
}

// Reads a BMP file header and check that it has the BMP magic number.
static void ReadBmpFileHeader(FILE *f, BitmapFileHeader *fileheader)
{
	fileheader->type = ReadS16(f);
	fileheader->size = ReadS32(f);
	fileheader->reserved1 = ReadS16(f);
	fileheader->reserved2 = ReadS16(f);
	fileheader->offBits = ReadS32(f);

	ReleaseAssert(fileheader->type == 19778, "BMP file seems corrupt");
}

// Reads information from a BMP file header.
static void ReadWinBmpInfoHeader(FILE *f, BitmapInfoHeader *infoheader)
{
	WinBmpInfoHeader win_infoheader;

	win_infoheader.width = ReadS32(f);
	win_infoheader.height = ReadS32(f);
	win_infoheader.planes = ReadS16(f);
	win_infoheader.bitCount = ReadS16(f);
	win_infoheader.compression = ReadS32(f);
	win_infoheader.sizeImage = ReadS32(f);
	win_infoheader.xPelsPerMeter = ReadS32(f);
	win_infoheader.biYPelsPerMeter = ReadS32(f);
	win_infoheader.biClrUsed = ReadS32(f);
	win_infoheader.biClrImportant = ReadS32(f);

	infoheader->width = win_infoheader.width;
	infoheader->height = win_infoheader.height;
	infoheader->bitCount = win_infoheader.bitCount;
	infoheader->compression = win_infoheader.compression;
}

static void ReadBmpPalette(int ncols, DfColour pal[256], FILE *f)
{
	for (int i = 0; i < ncols; i++)
	{
	    pal[i].b = ReadU8(f);
	    pal[i].g = ReadU8(f);
	    pal[i].r = ReadU8(f);
		pal[i].a = 255;
        ReadU8(f);
	}
}

// Support function for reading the 4 bit bitmap file format.
static void Read4BitLine(DfBitmap *bitmap, int length, FILE *f, DfColour pal[256], int y)
{
	for (int x = 0; x < length; x += 2)
	{
		uint8_t i = ReadU8(f);
		unsigned idx1 = i & 15;
		unsigned idx2 = (i >> 4) & 15;
		PutPix(bitmap, x+1, y, pal[idx1]);
		PutPix(bitmap, x, y, pal[idx2]);
	}
}

// Support function for reading the 8 bit bitmap file format.
static void Read8BitLine(DfBitmap *bitmap, int length, FILE *f, DfColour pal[256], int y)
{
	for (int x = 0; x < length; ++x)
	{
		uint8_t i = ReadU8(f);
		PutPix(bitmap, x, y, pal[i]);
	}

    // Skip any padding until we've read a multiple of 4 bytes.
    while (length & 3)
    {
        ReadU8(f);
        length++;
    }
}

// Support function for reading the 24 bit bitmap file format
static void Read24BitLine(DfBitmap *bitmap, int length, FILE *f, int y)
{
	DfColour c;
	int nbytes = 0;
	c.a = 255;

	for (int i = 0; i < length; i++)
	{
		c.b = ReadU8(f);
		c.g = ReadU8(f);
		c.r = ReadU8(f);
		PutPix(bitmap, i, y, c);
		nbytes += 3;
	}

	for (int padding = (4 - nbytes) & 3; padding; --padding)
		ReadU8(f);
}

// ****************************************************************************
// Public Functions
// ****************************************************************************

DfBitmap *LoadBmp(char const *filename)
{
    FILE *f = fopen(filename, "rb");
    if (!f)
        return NULL;

    BitmapFileHeader fileheader;
    ReadBmpFileHeader(f, &fileheader);

    uint32_t infoHeaderSize = ReadS32(f);
    ReleaseAssert(infoHeaderSize == WININFOHEADERSIZE, "Bitmap header size invalid (%i bytes). Is it a Windows BMP?", infoHeaderSize);

    BitmapInfoHeader infoheader;
    ReadWinBmpInfoHeader(f, &infoheader);
    ReleaseAssert(infoheader.compression == BMP_RGB, "Bitmap loader does not support RLE compressed bitmaps");

    int ncol = (fileheader.offBits - 54) / 4; // Calc num colours in palette.
    DfColour palette[256];
    ReadBmpPalette(ncol, palette, f);

    DfBitmap *bitmap = BitmapCreate(infoheader.width, infoheader.height);

    // Read the image
    for (int i = 0; i < (int)infoheader.height; ++i)
    {
        int y = bitmap->height - i - 1;
        switch (infoheader.bitCount)
        {
        case 4:
            Read4BitLine(bitmap, infoheader.width, f, palette, y);
            break;
        case 8:
            Read8BitLine(bitmap, infoheader.width, f, palette, y);
            break;
        case 24:
            Read24BitLine(bitmap, infoheader.width, f, y);
            break;
        default:
            DebugAssert(0);
            break;
        }
    }

    fclose(f);
    return bitmap;
}

bool SaveBmp(DfBitmap *bmp, char const *filename)
{
    FILE *f = fopen(filename, "wb");
    if (!f)
        return false;

    int w = bmp->width;
    int h = bmp->height;
    int fileSize = 54 + 3*w*h;  //w is your image width, h is image height, both int
    uint8_t *img = new uint8_t [3*w*h];
    memset(img, 0, sizeof(img));

    for (int x = 0; x < w; x++)
    {
        for (int j = 0; j < h; j++)
        {
            int y = (h-1) - j;
            DfColour c = GetPix(bmp, x, y);
            img[(x+y*w)*3+2] = c.r;
            img[(x+y*w)*3+1] = c.g;
            img[(x+y*w)*3+0] = c.b;
        }
    }

    uint8_t fileHeader[14] = {'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0};
    uint8_t infoHeader[40] = {40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0};
    uint8_t bmppad[3] = {0,0,0};

    fileHeader[2] = (uint8_t)(fileSize    );
    fileHeader[3] = (uint8_t)(fileSize>> 8);
    fileHeader[4] = (uint8_t)(fileSize>>16);
    fileHeader[5] = (uint8_t)(fileSize>>24);

    infoHeader[4] = (uint8_t)w;
    infoHeader[5] = (uint8_t)(w >> 8);
    infoHeader[6] = (uint8_t)(w >> 16);
    infoHeader[7] = (uint8_t)(w >> 24);
    infoHeader[8] = (uint8_t)h;
    infoHeader[9] = (uint8_t)(h >> 8);
    infoHeader[10] = (uint8_t)(h >> 16);
    infoHeader[11] = (uint8_t)(h >> 24);

    fwrite(fileHeader, 1, 14, f);
    fwrite(infoHeader, 1, 40, f);
    for(int i = 0; i < h; i++)
    {
        fwrite(img+(w*(h-i-1)*3), 3, w, f);
        fwrite(bmppad, 1, (4-(w*3)%4)%4, f);
    }
    fclose(f);

    delete [] img;
    return true;
}
<commit_msg>Added support for reading 1-bit BMP files. Also fixed calculation of number of padding bytes in 4-bit images.<commit_after>#include "df_bmp.h"

#include "df_bitmap.h"

#include <memory.h>
#include <stdint.h>
#include <stdio.h>

#define BMP_RGB				0
#define OS2INFOHEADERSIZE  12
#define WININFOHEADERSIZE  40

struct BitmapFileHeader
{
	uint16_t type;
	uint32_t size;
	uint16_t reserved1;
	uint16_t reserved2;
	uint32_t offBits;
};

struct BitmapInfoHeader
{
	uint32_t width;
	uint32_t height;
	uint16_t bitCount;
	uint32_t compression;
};

struct WinBmpInfoHeader
{
	uint32_t width;
	uint32_t height;
	uint16_t planes;
	uint16_t bitCount;
	uint32_t compression;
	uint32_t sizeImage;
	uint32_t xPelsPerMeter;
	uint32_t biYPelsPerMeter;
	uint32_t biClrUsed;
	uint32_t biClrImportant;
};

// ****************************************************************************
// Private Functions
// ****************************************************************************

static uint8_t ReadU8(FILE *file)
{
    return fgetc(file);
}

static short ReadS16(FILE *file)
{
    int b1 = fgetc(file);
    int b2 = fgetc(file);
    return ((b2 << 8) | b1);
}

static int ReadS32(FILE *file)
{
    int b1 = fgetc(file);
    int b2 = fgetc(file);
    int b3 = fgetc(file);
    int b4 = fgetc(file);
    return ((b4 << 24) | (b3 << 16) | (b2 << 8) | b1);
}

// Reads a BMP file header and check that it has the BMP magic number.
static void ReadBmpFileHeader(FILE *f, BitmapFileHeader *fileheader)
{
	fileheader->type = ReadS16(f);
	fileheader->size = ReadS32(f);
	fileheader->reserved1 = ReadS16(f);
	fileheader->reserved2 = ReadS16(f);
	fileheader->offBits = ReadS32(f);

	ReleaseAssert(fileheader->type == 19778, "BMP file seems corrupt");
}

// Reads information from a BMP file header.
static void ReadWinBmpInfoHeader(FILE *f, BitmapInfoHeader *infoheader)
{
	WinBmpInfoHeader win_infoheader;

	win_infoheader.width = ReadS32(f);
	win_infoheader.height = ReadS32(f);
	win_infoheader.planes = ReadS16(f);
	win_infoheader.bitCount = ReadS16(f);
	win_infoheader.compression = ReadS32(f);
	win_infoheader.sizeImage = ReadS32(f);
	win_infoheader.xPelsPerMeter = ReadS32(f);
	win_infoheader.biYPelsPerMeter = ReadS32(f);
	win_infoheader.biClrUsed = ReadS32(f);
	win_infoheader.biClrImportant = ReadS32(f);

	infoheader->width = win_infoheader.width;
	infoheader->height = win_infoheader.height;
	infoheader->bitCount = win_infoheader.bitCount;
	infoheader->compression = win_infoheader.compression;
}

static void ReadBmpPalette(int ncols, DfColour pal[256], FILE *f)
{
	for (int i = 0; i < ncols; i++)
	{
	    pal[i].b = ReadU8(f);
	    pal[i].g = ReadU8(f);
	    pal[i].r = ReadU8(f);
		pal[i].a = 255;
        ReadU8(f);
	}
}

static void SkipPadding(FILE *f, int width, int pixels_per_byte)
{
    // Skip any padding until we've read a multiple of 4 bytes.
    int num_bytes = (width + pixels_per_byte - 1) / pixels_per_byte;
    while (num_bytes & 3)
    {
        ReadU8(f);
        num_bytes++;
    }
}

static void Read1BitLine(DfBitmap *bitmap, int length, FILE *f, DfColour pal[256], int y)
{
    for (int x = 0; x < length; x += 8)
    {
        uint8_t i = ReadU8(f);
        for (int j = 0; j < 8; j++) {
            int idx = (i >> 7) & 1;
            PutPix(bitmap, x + j, y, pal[idx]);
            i <<= 1;
        }
    }

    SkipPadding(f, length, 8);
}

static void Read4BitLine(DfBitmap *bitmap, int length, FILE *f, DfColour pal[256], int y)
{
	for (int x = 0; x < length; x += 2)
	{
		uint8_t i = ReadU8(f);
		unsigned idx1 = i & 15;
		unsigned idx2 = (i >> 4) & 15;
		PutPix(bitmap, x+1, y, pal[idx1]);
		PutPix(bitmap, x, y, pal[idx2]);
	}

    SkipPadding(f, length, 2);
}

static void Read8BitLine(DfBitmap *bitmap, int length, FILE *f, DfColour pal[256], int y)
{
	for (int x = 0; x < length; ++x)
	{
		uint8_t i = ReadU8(f);
		PutPix(bitmap, x, y, pal[i]);
	}

    SkipPadding(f, length, 1);
}

static void Read24BitLine(DfBitmap *bitmap, int length, FILE *f, int y)
{
	DfColour c;
	int nbytes = 0;
	c.a = 255;

	for (int i = 0; i < length; i++)
	{
		c.b = ReadU8(f);
		c.g = ReadU8(f);
		c.r = ReadU8(f);
		PutPix(bitmap, i, y, c);
		nbytes += 3;
	}

	for (int padding = (4 - nbytes) & 3; padding; --padding)
		ReadU8(f);
}

// ****************************************************************************
// Public Functions
// ****************************************************************************

DfBitmap *LoadBmp(char const *filename)
{
    FILE *f = fopen(filename, "rb");
    if (!f)
        return NULL;

    BitmapFileHeader fileheader;
    ReadBmpFileHeader(f, &fileheader);

    uint32_t infoHeaderSize = ReadS32(f);
    ReleaseAssert(infoHeaderSize == WININFOHEADERSIZE, "Bitmap header size invalid (%i bytes). Is it a Windows BMP?", infoHeaderSize);

    BitmapInfoHeader infoheader;
    ReadWinBmpInfoHeader(f, &infoheader);
    ReleaseAssert(infoheader.compression == BMP_RGB, "Bitmap loader does not support RLE compressed bitmaps");

    int ncol = (fileheader.offBits - 54) / 4; // Calc num colours in palette.
    DfColour palette[256];
    ReadBmpPalette(ncol, palette, f);

    DfBitmap *bitmap = BitmapCreate(infoheader.width, infoheader.height);

    // Read the image
    for (int i = 0; i < (int)infoheader.height; ++i)
    {
        int y = bitmap->height - i - 1;
        switch (infoheader.bitCount)
        {
        case 1:
            Read1BitLine(bitmap, infoheader.width, f, palette, y);
            break;
        case 4:
            Read4BitLine(bitmap, infoheader.width, f, palette, y);
            break;
        case 8:
            Read8BitLine(bitmap, infoheader.width, f, palette, y);
            break;
        case 24:
            Read24BitLine(bitmap, infoheader.width, f, y);
            break;
        default:
            DebugAssert(0);
            break;
        }
    }

    fclose(f);
    return bitmap;
}

bool SaveBmp(DfBitmap *bmp, char const *filename)
{
    FILE *f = fopen(filename, "wb");
    if (!f)
        return false;

    int w = bmp->width;
    int h = bmp->height;
    int fileSize = 54 + 3*w*h;  //w is your image width, h is image height, both int
    uint8_t *img = new uint8_t [3*w*h];
    memset(img, 0, sizeof(img));

    for (int x = 0; x < w; x++)
    {
        for (int j = 0; j < h; j++)
        {
            int y = (h-1) - j;
            DfColour c = GetPix(bmp, x, y);
            img[(x+y*w)*3+2] = c.r;
            img[(x+y*w)*3+1] = c.g;
            img[(x+y*w)*3+0] = c.b;
        }
    }

    uint8_t fileHeader[14] = {'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0};
    uint8_t infoHeader[40] = {40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0};
    uint8_t bmppad[3] = {0,0,0};

    fileHeader[2] = (uint8_t)(fileSize    );
    fileHeader[3] = (uint8_t)(fileSize>> 8);
    fileHeader[4] = (uint8_t)(fileSize>>16);
    fileHeader[5] = (uint8_t)(fileSize>>24);

    infoHeader[4] = (uint8_t)w;
    infoHeader[5] = (uint8_t)(w >> 8);
    infoHeader[6] = (uint8_t)(w >> 16);
    infoHeader[7] = (uint8_t)(w >> 24);
    infoHeader[8] = (uint8_t)h;
    infoHeader[9] = (uint8_t)(h >> 8);
    infoHeader[10] = (uint8_t)(h >> 16);
    infoHeader[11] = (uint8_t)(h >> 24);

    fwrite(fileHeader, 1, 14, f);
    fwrite(infoHeader, 1, 40, f);
    for(int i = 0; i < h; i++)
    {
        fwrite(img+(w*(h-i-1)*3), 3, w, f);
        fwrite(bmppad, 1, (4-(w*3)%4)%4, f);
    }
    fclose(f);

    delete [] img;
    return true;
}
<|endoftext|>


<commit_before>/** @file

  A brief file description

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you 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.
 */

/*************************** -*- Mod: C++ -*- ******************************
  SSLSNIConfig.cc
   Created On      : 05/02/2017

   Description:
   SNI based Configuration in ATS
 ****************************************************************************/

#include "P_SSLSNI.h"
#include "tscore/Diags.h"
#include "tscore/SimpleTokenizer.h"
#include "P_SSLConfig.h"
#include "tscore/ink_memory.h"
#include "tscpp/util/TextView.h"
#include "tscore/I_Layout.h"
#include <sstream>
#include <pcre.h>

static ConfigUpdateHandler<SNIConfig> *sniConfigUpdate;
struct NetAccept;
std::unordered_map<int, SSLNextProtocolSet *> snpsMap;

const NextHopProperty *
SNIConfigParams::getPropertyConfig(const std::string &servername) const
{
  const NextHopProperty *nps = nullptr;
  for (auto &&item : next_hop_list) {
    if (pcre_exec(item.match, nullptr, servername.c_str(), servername.length(), 0, 0, nullptr, 0) >= 0) {
      // Found a match
      nps = &item.prop;
      break;
    }
  }
  return nps;
}

void
SNIConfigParams::loadSNIConfig()
{
  for (auto &item : Y_sni.items) {
    auto ai = sni_action_list.emplace(sni_action_list.end());
    ai->setGlobName(item.fqdn);
    Debug("ssl", "name: %s", item.fqdn.data());

    // set SNI based actions to be called in the ssl_servername_only callback
    if (item.disable_h2) {
      ai->actions.push_back(std::make_unique<DisableH2>());
    }
    if (item.verify_client_level != 255) {
      ai->actions.push_back(std::make_unique<VerifyClient>(item.verify_client_level));
    }
    if (!item.protocol_unset) {
      ai->actions.push_back(std::make_unique<TLSValidProtocols>(item.protocol_mask));
    }
    if (item.tunnel_destination.length() > 0) {
      ai->actions.push_back(std::make_unique<TunnelDestination>(item.tunnel_destination, item.tunnel_decrypt));
    }

    ai->actions.push_back(std::make_unique<SNI_IpAllow>(item.ip_allow, item.fqdn));

    // set the next hop properties
    SSLConfig::scoped_config params;
    auto clientCTX = params->getClientSSL_CTX();
    if (!item.client_cert.empty() && !item.client_key.empty()) {
      std::string certFilePath = Layout::get()->relative_to(params->clientCertPathOnly, item.client_cert.data());
      std::string keyFilePath  = Layout::get()->relative_to(params->clientKeyPathOnly, item.client_key.data());
      clientCTX = params->getCTX(certFilePath.c_str(), keyFilePath.c_str(), params->clientCACertFilename, params->clientCACertPath);
    }

    auto nps = next_hop_list.emplace(next_hop_list.end());
    nps->setGlobName(item.fqdn);
    nps->prop.verifyServerPolicy     = item.verify_server_policy;
    nps->prop.verifyServerProperties = item.verify_server_properties;
    nps->prop.ctx                    = clientCTX;
  } // end for
}

int SNIConfig::configid = 0;
/*definition of member functions of SNIConfigParams*/
SNIConfigParams::SNIConfigParams() {}

const actionVector *
SNIConfigParams::get(const std::string &servername) const
{
  for (auto retval = sni_action_list.begin(); retval != sni_action_list.end(); ++retval) {
    if (retval->match == nullptr && servername.length() == 0) {
      return &retval->actions;
    } else if (pcre_exec(retval->match, nullptr, servername.c_str(), servername.length(), 0, 0, nullptr, 0) >= 0) {
      return &retval->actions;
    }
  }
  return nullptr;
}

int
SNIConfigParams::Initialize()
{
  sni_filename = ats_stringdup(RecConfigReadConfigPath("proxy.config.ssl.servername.filename"));

  Note("loading %s", sni_filename);

  struct stat sbuf;
  if (stat(sni_filename, &sbuf) == -1 && errno == ENOENT) {
    Note("failed to reload ssl_server_name.yaml");
    Warning("Loading SNI configuration - filename: %s doesn't exist", sni_filename);
    return 1;
  }

  ts::Errata zret = Y_sni.loader(sni_filename);
  if (!zret.isOK()) {
    std::stringstream errMsg;
    errMsg << zret;
    Error("failed to load ssl_server_name.yaml: %s", errMsg.str().c_str());
    return 1;
  }

  loadSNIConfig();
  Note("ssl_server_name.yaml done reloading!");

  return 0;
}

SNIConfigParams::~SNIConfigParams()
{
  // sni_action_list and next_hop_list should cleanup with the params object
}

/*definition of member functions of SNIConfig*/
void
SNIConfig::startup()
{
  sniConfigUpdate = new ConfigUpdateHandler<SNIConfig>();
  sniConfigUpdate->attach("proxy.config.ssl.servername.filename");
  reconfigure();
}

void
SNIConfig::cloneProtoSet()
{
  SCOPED_MUTEX_LOCK(lock, naVecMutex, this_ethread());
  for (auto na : naVec) {
    if (na->snpa) {
      auto snps = na->snpa->cloneProtoSet();
      snps->unregisterEndpoint(TS_ALPN_PROTOCOL_HTTP_2_0, nullptr);
      snpsMap.emplace(na->id, snps);
    }
  }
}

void
SNIConfig::reconfigure()
{
  SNIConfigParams *params = new SNIConfigParams;

  params->Initialize();
  configid = configProcessor.set(configid, params);
}

SNIConfigParams *
SNIConfig::acquire()
{
  return (SNIConfigParams *)configProcessor.get(configid);
}

void
SNIConfig::release(SNIConfigParams *params)
{
  configProcessor.release(configid, params);
}
<commit_msg>Load client key event if only the certificate file is specified.<commit_after>/** @file

  A brief file description

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you 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.
 */

/*************************** -*- Mod: C++ -*- ******************************
  SSLSNIConfig.cc
   Created On      : 05/02/2017

   Description:
   SNI based Configuration in ATS
 ****************************************************************************/

#include "P_SSLSNI.h"
#include "tscore/Diags.h"
#include "tscore/SimpleTokenizer.h"
#include "P_SSLConfig.h"
#include "tscore/ink_memory.h"
#include "tscpp/util/TextView.h"
#include "tscore/I_Layout.h"
#include <sstream>
#include <pcre.h>

static ConfigUpdateHandler<SNIConfig> *sniConfigUpdate;
struct NetAccept;
std::unordered_map<int, SSLNextProtocolSet *> snpsMap;

const NextHopProperty *
SNIConfigParams::getPropertyConfig(const std::string &servername) const
{
  const NextHopProperty *nps = nullptr;
  for (auto &&item : next_hop_list) {
    if (pcre_exec(item.match, nullptr, servername.c_str(), servername.length(), 0, 0, nullptr, 0) >= 0) {
      // Found a match
      nps = &item.prop;
      break;
    }
  }
  return nps;
}

void
SNIConfigParams::loadSNIConfig()
{
  for (auto &item : Y_sni.items) {
    auto ai = sni_action_list.emplace(sni_action_list.end());
    ai->setGlobName(item.fqdn);
    Debug("ssl", "name: %s", item.fqdn.data());

    // set SNI based actions to be called in the ssl_servername_only callback
    if (item.disable_h2) {
      ai->actions.push_back(std::make_unique<DisableH2>());
    }
    if (item.verify_client_level != 255) {
      ai->actions.push_back(std::make_unique<VerifyClient>(item.verify_client_level));
    }
    if (!item.protocol_unset) {
      ai->actions.push_back(std::make_unique<TLSValidProtocols>(item.protocol_mask));
    }
    if (item.tunnel_destination.length() > 0) {
      ai->actions.push_back(std::make_unique<TunnelDestination>(item.tunnel_destination, item.tunnel_decrypt));
    }

    ai->actions.push_back(std::make_unique<SNI_IpAllow>(item.ip_allow, item.fqdn));

    // set the next hop properties
    SSLConfig::scoped_config params;
    auto clientCTX = params->getClientSSL_CTX();
    // Load if we have at least specified the client certificate
    if (!item.client_cert.empty()) {
      std::string certFilePath = Layout::get()->relative_to(params->clientCertPathOnly, item.client_cert.data());
      std::string keyFilePath;
      if (!item.client_key.empty()) {
        keyFilePath = Layout::get()->relative_to(params->clientKeyPathOnly, item.client_key.data());
      }
      clientCTX = params->getCTX(certFilePath.c_str(), keyFilePath.c_str(), params->clientCACertFilename, params->clientCACertPath);
    }

    auto nps = next_hop_list.emplace(next_hop_list.end());
    nps->setGlobName(item.fqdn);
    nps->prop.verifyServerPolicy     = item.verify_server_policy;
    nps->prop.verifyServerProperties = item.verify_server_properties;
    nps->prop.ctx                    = clientCTX;
  } // end for
}

int SNIConfig::configid = 0;
/*definition of member functions of SNIConfigParams*/
SNIConfigParams::SNIConfigParams() {}

const actionVector *
SNIConfigParams::get(const std::string &servername) const
{
  for (auto retval = sni_action_list.begin(); retval != sni_action_list.end(); ++retval) {
    if (retval->match == nullptr && servername.length() == 0) {
      return &retval->actions;
    } else if (pcre_exec(retval->match, nullptr, servername.c_str(), servername.length(), 0, 0, nullptr, 0) >= 0) {
      return &retval->actions;
    }
  }
  return nullptr;
}

int
SNIConfigParams::Initialize()
{
  sni_filename = ats_stringdup(RecConfigReadConfigPath("proxy.config.ssl.servername.filename"));

  Note("loading %s", sni_filename);

  struct stat sbuf;
  if (stat(sni_filename, &sbuf) == -1 && errno == ENOENT) {
    Note("failed to reload ssl_server_name.yaml");
    Warning("Loading SNI configuration - filename: %s doesn't exist", sni_filename);
    return 1;
  }

  ts::Errata zret = Y_sni.loader(sni_filename);
  if (!zret.isOK()) {
    std::stringstream errMsg;
    errMsg << zret;
    Error("failed to load ssl_server_name.yaml: %s", errMsg.str().c_str());
    return 1;
  }

  loadSNIConfig();
  Note("ssl_server_name.yaml done reloading!");

  return 0;
}

SNIConfigParams::~SNIConfigParams()
{
  // sni_action_list and next_hop_list should cleanup with the params object
}

/*definition of member functions of SNIConfig*/
void
SNIConfig::startup()
{
  sniConfigUpdate = new ConfigUpdateHandler<SNIConfig>();
  sniConfigUpdate->attach("proxy.config.ssl.servername.filename");
  reconfigure();
}

void
SNIConfig::cloneProtoSet()
{
  SCOPED_MUTEX_LOCK(lock, naVecMutex, this_ethread());
  for (auto na : naVec) {
    if (na->snpa) {
      auto snps = na->snpa->cloneProtoSet();
      snps->unregisterEndpoint(TS_ALPN_PROTOCOL_HTTP_2_0, nullptr);
      snpsMap.emplace(na->id, snps);
    }
  }
}

void
SNIConfig::reconfigure()
{
  SNIConfigParams *params = new SNIConfigParams;

  params->Initialize();
  configid = configProcessor.set(configid, params);
}

SNIConfigParams *
SNIConfig::acquire()
{
  return (SNIConfigParams *)configProcessor.get(configid);
}

void
SNIConfig::release(SNIConfigParams *params)
{
  configProcessor.release(configid, params);
}
<|endoftext|>