<commit_before>// Copyright (c) 2011 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 "content/browser/renderer_host/pepper_file_message_filter.h"

#include "base/callback.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/platform_file.h"
#include "base/process_util.h"
#include "content/browser/browser_context.h"
#include "content/browser/child_process_security_policy.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/common/pepper_file_messages.h"
#include "content/public/browser/browser_thread.h"
#include "ipc/ipc_platform_file.h"
#include "webkit/plugins/ppapi/file_path.h"

#if defined(OS_POSIX)
#include "base/file_descriptor_posix.h"
#endif

using content::BrowserThread;

// Used to check if the renderer has permission for the requested operation.
// TODO(viettrungluu): Verify these. They don't necessarily quite make sense,
// but it seems to be approximately what the file system code does.
const int kReadPermissions = base::PLATFORM_FILE_OPEN |
                             base::PLATFORM_FILE_READ |
                             base::PLATFORM_FILE_EXCLUSIVE_READ;
const int kWritePermissions = base::PLATFORM_FILE_OPEN |
                              base::PLATFORM_FILE_CREATE |
                              base::PLATFORM_FILE_CREATE_ALWAYS |
                              base::PLATFORM_FILE_OPEN_TRUNCATED |
                              base::PLATFORM_FILE_WRITE |
                              base::PLATFORM_FILE_EXCLUSIVE_WRITE |
                              base::PLATFORM_FILE_WRITE_ATTRIBUTES;

PepperFileMessageFilter::PepperFileMessageFilter(
    int child_id, content::BrowserContext* browser_context)
        : child_id_(child_id) {
  pepper_path_ =
      browser_context->GetPath().Append(FILE_PATH_LITERAL("Pepper Data"));
}

PepperFileMessageFilter::~PepperFileMessageFilter() {
  // This function should be called on the IO thread.
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
}

void PepperFileMessageFilter::OverrideThreadForMessage(
    const IPC::Message& message,
    BrowserThread::ID* thread) {
  if (IPC_MESSAGE_CLASS(message) == PepperFileMsgStart)
    *thread = BrowserThread::FILE;
}

bool PepperFileMessageFilter::OnMessageReceived(const IPC::Message& message,
                                                bool* message_was_ok) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP_EX(PepperFileMessageFilter, message, *message_was_ok)
    IPC_MESSAGE_HANDLER(PepperFileMsg_OpenFile, OnOpenFile)
    IPC_MESSAGE_HANDLER(PepperFileMsg_RenameFile, OnRenameFile)
    IPC_MESSAGE_HANDLER(PepperFileMsg_DeleteFileOrDir, OnDeleteFileOrDir)
    IPC_MESSAGE_HANDLER(PepperFileMsg_CreateDir, OnCreateDir)
    IPC_MESSAGE_HANDLER(PepperFileMsg_QueryFile, OnQueryFile)
    IPC_MESSAGE_HANDLER(PepperFileMsg_GetDirContents, OnGetDirContents)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP_EX()
  return handled;
}

void PepperFileMessageFilter::OnDestruct() const {
  BrowserThread::DeleteOnIOThread::Destruct(this);
}

// Called on the FILE thread:
void PepperFileMessageFilter::OnOpenFile(
    const webkit::ppapi::PepperFilePath& path,
    int flags,
    base::PlatformFileError* error,
    IPC::PlatformFileForTransit* file) {
  FilePath full_path = ValidateAndConvertPepperFilePath(path, flags);
  if (full_path.empty()) {
    *error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
    *file = IPC::InvalidPlatformFileForTransit();
    return;
  }

  base::PlatformFile file_handle = base::CreatePlatformFile(
      full_path, flags, NULL, error);

  if (*error != base::PLATFORM_FILE_OK ||
      file_handle == base::kInvalidPlatformFileValue) {
    *file = IPC::InvalidPlatformFileForTransit();
    return;
  }

  // Make sure we didn't try to open a directory: directory fd shouldn't pass
  // to untrusted processes because they open security holes.
  base::PlatformFileInfo info;
  if (!base::GetPlatformFileInfo(file_handle, &info) || info.is_directory) {
    // When in doubt, throw it out.
    *error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
    *file = IPC::InvalidPlatformFileForTransit();
    return;
  }

#if defined(OS_WIN)
  // Duplicate the file handle so that the renderer process can access the file.
  if (!DuplicateHandle(GetCurrentProcess(), file_handle,
                       peer_handle(), file, 0, false,
                       DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
    // file_handle is closed whether or not DuplicateHandle succeeds.
    *error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
    *file = INVALID_HANDLE_VALUE;
  }
#else
  *file = base::FileDescriptor(file_handle, true);
#endif
}

void PepperFileMessageFilter::OnRenameFile(
    const webkit::ppapi::PepperFilePath& from_path,
    const webkit::ppapi::PepperFilePath& to_path,
    base::PlatformFileError* error) {
  FilePath from_full_path = ValidateAndConvertPepperFilePath(from_path,
                                                             kWritePermissions);
  FilePath to_full_path = ValidateAndConvertPepperFilePath(to_path,
                                                           kWritePermissions);
  if (from_full_path.empty() || to_full_path.empty()) {
    *error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
    return;
  }

  bool result = file_util::Move(from_full_path, to_full_path);
  *error = result ? base::PLATFORM_FILE_OK
                  : base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
}

void PepperFileMessageFilter::OnDeleteFileOrDir(
    const webkit::ppapi::PepperFilePath& path,
    bool recursive,
    base::PlatformFileError* error) {
  FilePath full_path = ValidateAndConvertPepperFilePath(path,
                                                        kWritePermissions);
  if (full_path.empty()) {
    *error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
    return;
  }

  bool result = file_util::Delete(full_path, recursive);
  *error = result ? base::PLATFORM_FILE_OK
                  : base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
}

void PepperFileMessageFilter::OnCreateDir(
    const webkit::ppapi::PepperFilePath& path,
    base::PlatformFileError* error) {
  FilePath full_path = ValidateAndConvertPepperFilePath(path,
                                                        kWritePermissions);
  if (full_path.empty()) {
    *error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
    return;
  }

  bool result = file_util::CreateDirectory(full_path);
  *error = result ? base::PLATFORM_FILE_OK
                  : base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
}

void PepperFileMessageFilter::OnQueryFile(
    const webkit::ppapi::PepperFilePath& path,
    base::PlatformFileInfo* info,
    base::PlatformFileError* error) {
  FilePath full_path = ValidateAndConvertPepperFilePath(path, kReadPermissions);
  if (full_path.empty()) {
    *error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
    return;
  }

  bool result = file_util::GetFileInfo(full_path, info);
  *error = result ? base::PLATFORM_FILE_OK
                  : base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
}

void PepperFileMessageFilter::OnGetDirContents(
    const webkit::ppapi::PepperFilePath& path,
    webkit::ppapi::DirContents* contents,
    base::PlatformFileError* error) {
  FilePath full_path = ValidateAndConvertPepperFilePath(path, kReadPermissions);
  if (full_path.empty()) {
    *error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
    return;
  }

  contents->clear();

  file_util::FileEnumerator enumerator(
      full_path, false,
      static_cast<file_util::FileEnumerator::FileType>(
          file_util::FileEnumerator::FILES |
          file_util::FileEnumerator::DIRECTORIES |
          file_util::FileEnumerator::INCLUDE_DOT_DOT));

  while (!enumerator.Next().empty()) {
    file_util::FileEnumerator::FindInfo info;
    enumerator.GetFindInfo(&info);
    webkit::ppapi::DirEntry entry = {
      file_util::FileEnumerator::GetFilename(info),
      file_util::FileEnumerator::IsDirectory(info)
    };
    contents->push_back(entry);
  }

  *error = base::PLATFORM_FILE_OK;
}

FilePath PepperFileMessageFilter::ValidateAndConvertPepperFilePath(
    const webkit::ppapi::PepperFilePath& pepper_path, int flags) {
  FilePath file_path;  // Empty path returned on error.
  switch(pepper_path.domain()) {
    case webkit::ppapi::PepperFilePath::DOMAIN_ABSOLUTE:
// TODO(viettrungluu): This could be dangerous if not 100% right, so let's be
// conservative and only enable it when requested.
#if defined(ENABLE_FLAPPER_HACKS)
      if (pepper_path.path().IsAbsolute() &&
          ChildProcessSecurityPolicy::GetInstance()->HasPermissionsForFile(
              child_id(), pepper_path.path(), flags))
        file_path = pepper_path.path();
#else
      NOTIMPLEMENTED();
#endif  // ENABLE_FLAPPER_HACKS
      break;
    case webkit::ppapi::PepperFilePath::DOMAIN_MODULE_LOCAL:
      if (!pepper_path.path().IsAbsolute() &&
          !pepper_path.path().ReferencesParent())
        file_path = pepper_path_.Append(pepper_path.path());
      break;
    default:
      NOTREACHED();
      break;
  }
  return file_path;
}
<commit_msg>Enable |ValidateAndConvertPepperFilePath()| for domain-absolute paths without ENABLE_FLAPPER_HACKS.<commit_after>// Copyright (c) 2011 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 "content/browser/renderer_host/pepper_file_message_filter.h"

#include "base/callback.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/platform_file.h"
#include "base/process_util.h"
#include "content/browser/browser_context.h"
#include "content/browser/child_process_security_policy.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/common/pepper_file_messages.h"
#include "content/public/browser/browser_thread.h"
#include "ipc/ipc_platform_file.h"
#include "webkit/plugins/ppapi/file_path.h"

#if defined(OS_POSIX)
#include "base/file_descriptor_posix.h"
#endif

using content::BrowserThread;

// Used to check if the renderer has permission for the requested operation.
// TODO(viettrungluu): Verify these. They don't necessarily quite make sense,
// but it seems to be approximately what the file system code does.
const int kReadPermissions = base::PLATFORM_FILE_OPEN |
                             base::PLATFORM_FILE_READ |
                             base::PLATFORM_FILE_EXCLUSIVE_READ;
const int kWritePermissions = base::PLATFORM_FILE_OPEN |
                              base::PLATFORM_FILE_CREATE |
                              base::PLATFORM_FILE_CREATE_ALWAYS |
                              base::PLATFORM_FILE_OPEN_TRUNCATED |
                              base::PLATFORM_FILE_WRITE |
                              base::PLATFORM_FILE_EXCLUSIVE_WRITE |
                              base::PLATFORM_FILE_WRITE_ATTRIBUTES;

PepperFileMessageFilter::PepperFileMessageFilter(
    int child_id, content::BrowserContext* browser_context)
        : child_id_(child_id) {
  pepper_path_ =
      browser_context->GetPath().Append(FILE_PATH_LITERAL("Pepper Data"));
}

PepperFileMessageFilter::~PepperFileMessageFilter() {
  // This function should be called on the IO thread.
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
}

void PepperFileMessageFilter::OverrideThreadForMessage(
    const IPC::Message& message,
    BrowserThread::ID* thread) {
  if (IPC_MESSAGE_CLASS(message) == PepperFileMsgStart)
    *thread = BrowserThread::FILE;
}

bool PepperFileMessageFilter::OnMessageReceived(const IPC::Message& message,
                                                bool* message_was_ok) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP_EX(PepperFileMessageFilter, message, *message_was_ok)
    IPC_MESSAGE_HANDLER(PepperFileMsg_OpenFile, OnOpenFile)
    IPC_MESSAGE_HANDLER(PepperFileMsg_RenameFile, OnRenameFile)
    IPC_MESSAGE_HANDLER(PepperFileMsg_DeleteFileOrDir, OnDeleteFileOrDir)
    IPC_MESSAGE_HANDLER(PepperFileMsg_CreateDir, OnCreateDir)
    IPC_MESSAGE_HANDLER(PepperFileMsg_QueryFile, OnQueryFile)
    IPC_MESSAGE_HANDLER(PepperFileMsg_GetDirContents, OnGetDirContents)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP_EX()
  return handled;
}

void PepperFileMessageFilter::OnDestruct() const {
  BrowserThread::DeleteOnIOThread::Destruct(this);
}

// Called on the FILE thread:
void PepperFileMessageFilter::OnOpenFile(
    const webkit::ppapi::PepperFilePath& path,
    int flags,
    base::PlatformFileError* error,
    IPC::PlatformFileForTransit* file) {
  FilePath full_path = ValidateAndConvertPepperFilePath(path, flags);
  if (full_path.empty()) {
    *error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
    *file = IPC::InvalidPlatformFileForTransit();
    return;
  }

  base::PlatformFile file_handle = base::CreatePlatformFile(
      full_path, flags, NULL, error);

  if (*error != base::PLATFORM_FILE_OK ||
      file_handle == base::kInvalidPlatformFileValue) {
    *file = IPC::InvalidPlatformFileForTransit();
    return;
  }

  // Make sure we didn't try to open a directory: directory fd shouldn't pass
  // to untrusted processes because they open security holes.
  base::PlatformFileInfo info;
  if (!base::GetPlatformFileInfo(file_handle, &info) || info.is_directory) {
    // When in doubt, throw it out.
    *error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
    *file = IPC::InvalidPlatformFileForTransit();
    return;
  }

#if defined(OS_WIN)
  // Duplicate the file handle so that the renderer process can access the file.
  if (!DuplicateHandle(GetCurrentProcess(), file_handle,
                       peer_handle(), file, 0, false,
                       DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
    // file_handle is closed whether or not DuplicateHandle succeeds.
    *error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
    *file = INVALID_HANDLE_VALUE;
  }
#else
  *file = base::FileDescriptor(file_handle, true);
#endif
}

void PepperFileMessageFilter::OnRenameFile(
    const webkit::ppapi::PepperFilePath& from_path,
    const webkit::ppapi::PepperFilePath& to_path,
    base::PlatformFileError* error) {
  FilePath from_full_path = ValidateAndConvertPepperFilePath(from_path,
                                                             kWritePermissions);
  FilePath to_full_path = ValidateAndConvertPepperFilePath(to_path,
                                                           kWritePermissions);
  if (from_full_path.empty() || to_full_path.empty()) {
    *error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
    return;
  }

  bool result = file_util::Move(from_full_path, to_full_path);
  *error = result ? base::PLATFORM_FILE_OK
                  : base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
}

void PepperFileMessageFilter::OnDeleteFileOrDir(
    const webkit::ppapi::PepperFilePath& path,
    bool recursive,
    base::PlatformFileError* error) {
  FilePath full_path = ValidateAndConvertPepperFilePath(path,
                                                        kWritePermissions);
  if (full_path.empty()) {
    *error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
    return;
  }

  bool result = file_util::Delete(full_path, recursive);
  *error = result ? base::PLATFORM_FILE_OK
                  : base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
}

void PepperFileMessageFilter::OnCreateDir(
    const webkit::ppapi::PepperFilePath& path,
    base::PlatformFileError* error) {
  FilePath full_path = ValidateAndConvertPepperFilePath(path,
                                                        kWritePermissions);
  if (full_path.empty()) {
    *error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
    return;
  }

  bool result = file_util::CreateDirectory(full_path);
  *error = result ? base::PLATFORM_FILE_OK
                  : base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
}

void PepperFileMessageFilter::OnQueryFile(
    const webkit::ppapi::PepperFilePath& path,
    base::PlatformFileInfo* info,
    base::PlatformFileError* error) {
  FilePath full_path = ValidateAndConvertPepperFilePath(path, kReadPermissions);
  if (full_path.empty()) {
    *error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
    return;
  }

  bool result = file_util::GetFileInfo(full_path, info);
  *error = result ? base::PLATFORM_FILE_OK
                  : base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
}

void PepperFileMessageFilter::OnGetDirContents(
    const webkit::ppapi::PepperFilePath& path,
    webkit::ppapi::DirContents* contents,
    base::PlatformFileError* error) {
  FilePath full_path = ValidateAndConvertPepperFilePath(path, kReadPermissions);
  if (full_path.empty()) {
    *error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
    return;
  }

  contents->clear();

  file_util::FileEnumerator enumerator(
      full_path, false,
      static_cast<file_util::FileEnumerator::FileType>(
          file_util::FileEnumerator::FILES |
          file_util::FileEnumerator::DIRECTORIES |
          file_util::FileEnumerator::INCLUDE_DOT_DOT));

  while (!enumerator.Next().empty()) {
    file_util::FileEnumerator::FindInfo info;
    enumerator.GetFindInfo(&info);
    webkit::ppapi::DirEntry entry = {
      file_util::FileEnumerator::GetFilename(info),
      file_util::FileEnumerator::IsDirectory(info)
    };
    contents->push_back(entry);
  }

  *error = base::PLATFORM_FILE_OK;
}

FilePath PepperFileMessageFilter::ValidateAndConvertPepperFilePath(
    const webkit::ppapi::PepperFilePath& pepper_path, int flags) {
  FilePath file_path;  // Empty path returned on error.
  switch(pepper_path.domain()) {
    case webkit::ppapi::PepperFilePath::DOMAIN_ABSOLUTE:
      if (pepper_path.path().IsAbsolute() &&
          ChildProcessSecurityPolicy::GetInstance()->HasPermissionsForFile(
              child_id(), pepper_path.path(), flags))
        file_path = pepper_path.path();
      break;
    case webkit::ppapi::PepperFilePath::DOMAIN_MODULE_LOCAL:
      if (!pepper_path.path().IsAbsolute() &&
          !pepper_path.path().ReferencesParent())
        file_path = pepper_path_.Append(pepper_path.path());
      break;
    default:
      NOTREACHED();
      break;
  }
  return file_path;
}
<|endoftext|>


<commit_before>#include "trace.h"
#include "lib/output.h"
#include "lib/image.h"
#include "lib/lambertian.h"
#include "lib/range.h"
#include "lib/runtime.h"
#include "lib/triangle.h"
#include "lib/stats.h"
#include "lib/xorshift.h"

#include <assimp/Importer.hpp>      // C++ importer interface
#include <assimp/scene.h>           // Output data structure
#include <assimp/postprocess.h>     // Post processing flags
#include <docopt.h>
#include <ThreadPool.h>

#include <math.h>
#include <vector>
#include <map>
#include <iostream>
#include <unordered_set>
#include <chrono>

Color trace(const Vec& origin, const Vec& dir,
        const Tree& triangles_tree, const std::vector<Light>& lights,
        int depth, const Configuration& conf)
{
    //xorshift64star<float> uniform{4};

    Stats::instance().num_rays += 1;

    if (depth > conf.max_depth) {
        return {};
    }

    // intersection
    float dist_to_triangle, s, t;
    auto triangle_pt = triangles_tree.intersect(
        aiRay(origin, dir), dist_to_triangle, s, t);
    if (!triangle_pt) {
        return conf.bg_color;
    }

    // simple raycast
    const auto& triangle = *triangle_pt;
    auto result = triangle.diffuse;
    result.a = dist_to_triangle;
    //Color result { uniform(), uniform(), uniform(), dist_to_triangle};
    return result;
}

Triangles triangles_from_scene(const aiScene* scene) {
    Triangles triangles;
    for (auto node : make_range(
            scene->mRootNode->mChildren, scene->mRootNode->mNumChildren))
    {
        if (node->mNumMeshes == 0) {
            continue;
        }

        const auto& T = node->mTransformation;
        const aiMatrix3x3 Tp(T);  // trafo without translation

        for (auto mesh_index : make_range(node->mMeshes, node->mNumMeshes)) {
            const auto& mesh = *scene->mMeshes[mesh_index];

            aiColor4D ambient, diffuse;
            scene->mMaterials[mesh.mMaterialIndex]->Get(
                AI_MATKEY_COLOR_AMBIENT, ambient);
            scene->mMaterials[mesh.mMaterialIndex]->Get(
                AI_MATKEY_COLOR_DIFFUSE, diffuse);

            for (aiFace face : make_range(mesh.mFaces, mesh.mNumFaces)) {
                assert(face.mNumIndices == 3);
                triangles.push_back(Triangle{
                    // vertices
                    {{
                        T * mesh.mVertices[face.mIndices[0]],
                        T * mesh.mVertices[face.mIndices[1]],
                        T * mesh.mVertices[face.mIndices[2]]
                    }},
                    // normals
                    {{
                        Tp * mesh.mNormals[face.mIndices[0]],
                        Tp * mesh.mNormals[face.mIndices[1]],
                        Tp * mesh.mNormals[face.mIndices[2]]
                    }},
                    ambient,
                    diffuse
                });
            }
        }
    }
    return triangles;
}

static const char USAGE[] =
R"(Usage: raytracer <filename> [options]

Options:
  -w --width=<px>                   Width of the image [default: 640].
  -a --aspect=<num>                 Aspect ratio of the image. If the model has
                                    specified the aspect ratio, it will be
                                    used. Otherwise default value is 1.
  -d --max-depth=<int>              Maximum recursion depth for raytracing
                                    [default: 3].
  --shadow=<float>                  Intensity of shadow [default: 0.5].
  --background=<3x float>           Background color [default: 0 0 0].
  -p --pixel-samples=<int>          Number of samples per pixel [default: 1].
  -m --monte-carlo-samples=<int>    Monto Carlo samples per ray [default: 8].
                                    Used only in pathtracer.
  -t --threads=<int>                Number of threads [default: 1].
  --inverse-gamma=<float>           Inverse of gamma for gamma correction
                                    [default: 0.454545].
  --no-gamma-correction             Disables gamma correction.
)";

int main(int argc, char const *argv[])
{
    // parameters
    std::map<std::string, docopt::value> args =
        docopt::docopt(USAGE, {argv + 1, argv + argc}, true, "raytracer 0.2");

    const Configuration conf { args["--max-depth"].asLong()
                             , std::stof(args["--shadow"].asString())
                             , args["--pixel-samples"].asLong()
                             , args["--monte-carlo-samples"].asLong()
                             , args["--threads"].asLong()
                             , args["--background"].asString()
                             , std::stof(args["--inverse-gamma"].asString())
                             , args["--no-gamma-correction"].asBool()
                             };

    // import scene
    Assimp::Importer importer;
    const aiScene* scene = importer.ReadFile(
        args["<filename>"].asString().c_str(),
        aiProcess_CalcTangentSpace       |
        aiProcess_Triangulate            |
        aiProcess_JoinIdenticalVertices  |
        aiProcess_GenNormals             |
        aiProcess_SortByPType);

    if (!scene) {
        std::cout << importer.GetErrorString() << std::endl;
        return 1;
    }

    // setup camera
    assert(scene->mNumCameras == 1);  // we can deal only with a single camera
    auto& sceneCam = *scene->mCameras[0];
    if (args["--aspect"]) {
        sceneCam.mAspect = std::stof(args["--aspect"].asString());
        assert(sceneCam.mAspect > 0);
    } else if (sceneCam.mAspect == 0) {
        sceneCam.mAspect = 1.f;
    }
    auto* camNode = scene->mRootNode->FindNode(sceneCam.mName);
    assert(camNode != nullptr);
    const Camera cam(camNode->mTransformation, sceneCam);

    // setup light
    // we can deal only with one single or no light at all
    assert(scene->mNumLights == 0 || scene->mNumLights == 1);
    std::vector<Light> lights;
    if(scene->mNumLights == 1) {
        auto& rawLight = *scene->mLights[0];

        auto* lightNode = scene->mRootNode->FindNode(rawLight.mName);
        assert(lightNode != nullptr);
        const auto& LT = lightNode->mTransformation;
        lights.push_back(
            { LT * aiVector3D()
            , aiColor4D
                { rawLight.mColorDiffuse.r
                , rawLight.mColorDiffuse.g
                , rawLight.mColorDiffuse.b
                , 1
                }
            });
    }

    // load triangles from the scene into a kd-tree
    auto triangles = triangles_from_scene(scene);
    Stats::instance().num_triangles = triangles.size();
    Tree tree(std::move(triangles));

    //
    // Raytracer
    //

    int width = args["--width"].asLong();
    assert(width > 0);
    int height = width / cam.mAspect;

    Image image(width, height);
    {
        Runtime rt(Stats::instance().runtime_ms);

        std::cerr << "Rendering          ";

        ThreadPool pool(conf.num_threads);
        std::vector<std::future<void>> tasks;

        for (int y = 0; y < height; ++y) {
            tasks.emplace_back(pool.enqueue([
                    &image, &cam, &tree, &lights, width, height, y, &conf]()
            {
                float dx, dy;
                xorshift64star<float> gen(42);

                for (int x = 0; x < width; ++x) {
                    for (int i = 0; i < conf.num_pixel_samples; ++i) {
                        dx = gen();
                        dy = gen();

                        auto cam_dir = cam.raster2cam(
                            aiVector2D(x + dx, y + dy), width, height);

                        Stats::instance().num_prim_rays += 1;
                        image(x, y) += trace(cam.mPosition, cam_dir, tree,
                            lights, 0, conf);
                    }
                    image(x, y) /=
                        static_cast<float>(conf.num_pixel_samples);

                    // gamma correction
                    if (conf.gamma_correction_enabled) {
                        image(x, y).r = powf(image(x, y).r, conf.inverse_gamma);
                        image(x, y).g = powf(image(x, y).g, conf.inverse_gamma);
                        image(x, y).b = powf(image(x, y).b, conf.inverse_gamma);
                    }
                }
            }));
        }

        long completed = 0;

        for (auto& task: tasks) {
            task.get();
            completed += 1;
            float progress = static_cast<float>(completed) / tasks.size();
            int bar_width = progress * 20;
            std::cerr
                << "\rRendering          "
                << "[" << std::string(bar_width, '-')
                << std::string(20 - bar_width, ' ') << "] "
                << std::setfill(' ') << std::setw(6)
                << std::fixed << std::setprecision(2) << (progress * 100.0) << '%';
            std::cerr.flush();
        }
        std::cerr << std::endl;

        // Render feature lines after
        // "Ray Tracing NPR-Style Feature Lines" by Choudhury and Parker.
        std::cerr << "Drawing mesh lines ";
        std::vector<std::future<void>> mesh_tasks;
        float offset = 1.f;
        std::vector<Vec2> offsets =
            { Vec2(0.f, 0.f)
            , Vec2(offset, 0.f)
            , Vec2(offset, offset)
            , Vec2(0.f, offset)
            , Vec2(0.f, offset / 2)
            , Vec2(offset / 2, offset)
            , Vec2(offset, offset / 2)
            , Vec2(offset / 2, 0.f)
            };
        for (int y = 0; y < height; ++y) {
            mesh_tasks.emplace_back(pool.enqueue([
                    &image, &offsets, &cam, &tree, &lights, width, height, y, &conf]()
            {
                for (int x = 0; x < width; ++x) {
                    float dist_to_triangle, s, t;
                    std::unordered_set<std::uintptr_t> triangle_ids;

                    // Shoot center ray.
                    auto cam_dir = cam.raster2cam(
                        aiVector2D(x + 0.5f, y + 0.5f), width, height);
                    auto center_id = reinterpret_cast<std::uintptr_t>(tree.intersect(
                        Ray(cam.mPosition, cam_dir), dist_to_triangle, s, t));
                    triangle_ids.insert(center_id);

                    // Sample disc rays around center.
                    // TODO: Sample disc with Poisson or similar.
                    for ( auto offset : offsets) {
                        cam_dir = cam.raster2cam(
                            aiVector2D(x + offset[0], y + offset[1]), width, height);
                        auto triangle_pt = reinterpret_cast<std::uintptr_t>(tree.intersect(
                            Ray(cam.mPosition, cam_dir), dist_to_triangle, s, t));
                        triangle_ids.insert(triangle_pt);
                    }

                    const float M_2 = 0.5f * offsets.size();
                    // All hit primitives except the one hit by center.
                    const float m = triangle_ids.size() - 1.f;
                    float e = std::pow( std::abs(m - M_2) / M_2, 10 );
                    image(x, y) = image(x, y) * (e);
                }
            }));
        }

        completed = 0;
        for (auto& task: mesh_tasks) {
            task.get();
            completed += 1;
            float progress = static_cast<float>(completed) / mesh_tasks.size();
            int bar_width = progress * 20;
            std::cerr
                << "\rDrawing mesh lines "
                << "[" << std::string(bar_width, '-')
                << std::string(20 - bar_width, ' ') << "] "
                << std::setfill(' ') << std::setw(6)
                << std::fixed << std::setprecision(2) << (progress * 100.0) << '%';
            std::cerr.flush();
        }
        std::cerr << std::endl;
    }

    // output stats
    std::cerr << Stats::instance() << std::endl;

    // output image
    std::cout << image << std::endl;
    return 0;
}
<commit_msg>Don't cast triangle pointers.<commit_after>#include "trace.h"
#include "lib/output.h"
#include "lib/image.h"
#include "lib/lambertian.h"
#include "lib/range.h"
#include "lib/runtime.h"
#include "lib/triangle.h"
#include "lib/stats.h"
#include "lib/xorshift.h"

#include <assimp/Importer.hpp>      // C++ importer interface
#include <assimp/scene.h>           // Output data structure
#include <assimp/postprocess.h>     // Post processing flags
#include <docopt.h>
#include <ThreadPool.h>

#include <math.h>
#include <vector>
#include <map>
#include <iostream>
#include <unordered_set>
#include <chrono>

Color trace(const Vec& origin, const Vec& dir,
        const Tree& triangles_tree, const std::vector<Light>& /* lights */,
        int depth, const Configuration& conf)
{
    //xorshift64star<float> uniform{4};

    Stats::instance().num_rays += 1;

    if (depth > conf.max_depth) {
        return {};
    }

    // intersection
    float dist_to_triangle, s, t;
    auto triangle_pt = triangles_tree.intersect(
        aiRay(origin, dir), dist_to_triangle, s, t);
    if (!triangle_pt) {
        return conf.bg_color;
    }

    // simple raycast
    const auto& triangle = *triangle_pt;
    auto result = triangle.diffuse;
    result.a = dist_to_triangle;
    //Color result { uniform(), uniform(), uniform(), dist_to_triangle};
    return result;
}

Triangles triangles_from_scene(const aiScene* scene) {
    Triangles triangles;
    for (auto node : make_range(
            scene->mRootNode->mChildren, scene->mRootNode->mNumChildren))
    {
        if (node->mNumMeshes == 0) {
            continue;
        }

        const auto& T = node->mTransformation;
        const aiMatrix3x3 Tp(T);  // trafo without translation

        for (auto mesh_index : make_range(node->mMeshes, node->mNumMeshes)) {
            const auto& mesh = *scene->mMeshes[mesh_index];

            aiColor4D ambient, diffuse;
            scene->mMaterials[mesh.mMaterialIndex]->Get(
                AI_MATKEY_COLOR_AMBIENT, ambient);
            scene->mMaterials[mesh.mMaterialIndex]->Get(
                AI_MATKEY_COLOR_DIFFUSE, diffuse);

            for (aiFace face : make_range(mesh.mFaces, mesh.mNumFaces)) {
                assert(face.mNumIndices == 3);
                triangles.push_back(Triangle{
                    // vertices
                    {{
                        T * mesh.mVertices[face.mIndices[0]],
                        T * mesh.mVertices[face.mIndices[1]],
                        T * mesh.mVertices[face.mIndices[2]]
                    }},
                    // normals
                    {{
                        Tp * mesh.mNormals[face.mIndices[0]],
                        Tp * mesh.mNormals[face.mIndices[1]],
                        Tp * mesh.mNormals[face.mIndices[2]]
                    }},
                    ambient,
                    diffuse
                });
            }
        }
    }
    return triangles;
}

static const char USAGE[] =
R"(Usage: raytracer <filename> [options]

Options:
  -w --width=<px>                   Width of the image [default: 640].
  -a --aspect=<num>                 Aspect ratio of the image. If the model has
                                    specified the aspect ratio, it will be
                                    used. Otherwise default value is 1.
  -d --max-depth=<int>              Maximum recursion depth for raytracing
                                    [default: 3].
  --shadow=<float>                  Intensity of shadow [default: 0.5].
  --background=<3x float>           Background color [default: 0 0 0].
  -p --pixel-samples=<int>          Number of samples per pixel [default: 1].
  -m --monte-carlo-samples=<int>    Monto Carlo samples per ray [default: 8].
                                    Used only in pathtracer.
  -t --threads=<int>                Number of threads [default: 1].
  --inverse-gamma=<float>           Inverse of gamma for gamma correction
                                    [default: 0.454545].
  --no-gamma-correction             Disables gamma correction.
)";

int main(int argc, char const *argv[])
{
    // parameters
    std::map<std::string, docopt::value> args =
        docopt::docopt(USAGE, {argv + 1, argv + argc}, true, "raytracer 0.2");

    const Configuration conf { args["--max-depth"].asLong()
                             , std::stof(args["--shadow"].asString())
                             , args["--pixel-samples"].asLong()
                             , args["--monte-carlo-samples"].asLong()
                             , args["--threads"].asLong()
                             , args["--background"].asString()
                             , std::stof(args["--inverse-gamma"].asString())
                             , args["--no-gamma-correction"].asBool()
                             };

    // import scene
    Assimp::Importer importer;
    const aiScene* scene = importer.ReadFile(
        args["<filename>"].asString().c_str(),
        aiProcess_CalcTangentSpace       |
        aiProcess_Triangulate            |
        aiProcess_JoinIdenticalVertices  |
        aiProcess_GenNormals             |
        aiProcess_SortByPType);

    if (!scene) {
        std::cout << importer.GetErrorString() << std::endl;
        return 1;
    }

    // setup camera
    assert(scene->mNumCameras == 1);  // we can deal only with a single camera
    auto& sceneCam = *scene->mCameras[0];
    if (args["--aspect"]) {
        sceneCam.mAspect = std::stof(args["--aspect"].asString());
        assert(sceneCam.mAspect > 0);
    } else if (sceneCam.mAspect == 0) {
        sceneCam.mAspect = 1.f;
    }
    auto* camNode = scene->mRootNode->FindNode(sceneCam.mName);
    assert(camNode != nullptr);
    const Camera cam(camNode->mTransformation, sceneCam);

    // setup light
    // we can deal only with one single or no light at all
    assert(scene->mNumLights == 0 || scene->mNumLights == 1);
    std::vector<Light> lights;
    if(scene->mNumLights == 1) {
        auto& rawLight = *scene->mLights[0];

        auto* lightNode = scene->mRootNode->FindNode(rawLight.mName);
        assert(lightNode != nullptr);
        const auto& LT = lightNode->mTransformation;
        lights.push_back(
            { LT * aiVector3D()
            , aiColor4D
                { rawLight.mColorDiffuse.r
                , rawLight.mColorDiffuse.g
                , rawLight.mColorDiffuse.b
                , 1
                }
            });
    }

    // load triangles from the scene into a kd-tree
    auto triangles = triangles_from_scene(scene);
    Stats::instance().num_triangles = triangles.size();
    Tree tree(std::move(triangles));

    //
    // Raytracer
    //

    int width = args["--width"].asLong();
    assert(width > 0);
    int height = width / cam.mAspect;

    Image image(width, height);
    {
        Runtime rt(Stats::instance().runtime_ms);

        std::cerr << "Rendering          ";

        ThreadPool pool(conf.num_threads);
        std::vector<std::future<void>> tasks;

        for (int y = 0; y < height; ++y) {
            tasks.emplace_back(pool.enqueue([
                    &image, &cam, &tree, &lights, width, height, y, &conf]()
            {
                float dx, dy;
                xorshift64star<float> gen(42);

                for (int x = 0; x < width; ++x) {
                    for (int i = 0; i < conf.num_pixel_samples; ++i) {
                        dx = gen();
                        dy = gen();

                        auto cam_dir = cam.raster2cam(
                            aiVector2D(x + dx, y + dy), width, height);

                        Stats::instance().num_prim_rays += 1;
                        image(x, y) += trace(cam.mPosition, cam_dir, tree,
                            lights, 0, conf);
                    }
                    image(x, y) /=
                        static_cast<float>(conf.num_pixel_samples);

                    // gamma correction
                    if (conf.gamma_correction_enabled) {
                        image(x, y).r = powf(image(x, y).r, conf.inverse_gamma);
                        image(x, y).g = powf(image(x, y).g, conf.inverse_gamma);
                        image(x, y).b = powf(image(x, y).b, conf.inverse_gamma);
                    }
                }
            }));
        }

        long completed = 0;

        for (auto& task: tasks) {
            task.get();
            completed += 1;
            float progress = static_cast<float>(completed) / tasks.size();
            int bar_width = progress * 20;
            std::cerr
                << "\rRendering          "
                << "[" << std::string(bar_width, '-')
                << std::string(20 - bar_width, ' ') << "] "
                << std::setfill(' ') << std::setw(6)
                << std::fixed << std::setprecision(2) << (progress * 100.0) << '%';
            std::cerr.flush();
        }
        std::cerr << std::endl;

        // Render feature lines after
        // "Ray Tracing NPR-Style Feature Lines" by Choudhury and Parker.
        std::cerr << "Drawing mesh lines ";
        std::vector<std::future<void>> mesh_tasks;
        float offset = 1.f;
        std::vector<Vec2> offsets =
            { Vec2(0.f, 0.f)
            , Vec2(offset, 0.f)
            , Vec2(offset, offset)
            , Vec2(0.f, offset)
            , Vec2(0.f, offset / 2)
            , Vec2(offset / 2, offset)
            , Vec2(offset, offset / 2)
            , Vec2(offset / 2, 0.f)
            };
        for (int y = 0; y < height; ++y) {
            mesh_tasks.emplace_back(pool.enqueue([
                    &image, &offsets, &cam, &tree, &lights, width, height, y, &conf]()
            {
                for (int x = 0; x < width; ++x) {
                    float dist_to_triangle, s, t;
                    std::unordered_set<const Triangle*> triangle_ids;

                    // Shoot center ray.
                    auto cam_dir = cam.raster2cam(
                        aiVector2D(x + 0.5f, y + 0.5f), width, height);
                    auto center_id = tree.intersect(
                            Ray(cam.mPosition, cam_dir), dist_to_triangle, s, t);
                    triangle_ids.insert(center_id);

                    // Sample disc rays around center.
                    // TODO: Sample disc with Poisson or similar.
                    for ( auto offset : offsets) {
                        cam_dir = cam.raster2cam(
                            aiVector2D(x + offset[0], y + offset[1]), width, height);
                        auto triangle_pt = tree.intersect(
                            Ray(cam.mPosition, cam_dir), dist_to_triangle, s, t);
                        triangle_ids.insert(triangle_pt);
                    }

                    const float M_2 = 0.5f * offsets.size();
                    // All hit primitives except the one hit by center.
                    const float m = triangle_ids.size() - 1.f;
                    float e = std::pow( std::abs(m - M_2) / M_2, 10 );
                    image(x, y) = image(x, y) * (e);
                }
            }));
        }

        completed = 0;
        for (auto& task: mesh_tasks) {
            task.get();
            completed += 1;
            float progress = static_cast<float>(completed) / mesh_tasks.size();
            int bar_width = progress * 20;
            std::cerr
                << "\rDrawing mesh lines "
                << "[" << std::string(bar_width, '-')
                << std::string(20 - bar_width, ' ') << "] "
                << std::setfill(' ') << std::setw(6)
                << std::fixed << std::setprecision(2) << (progress * 100.0) << '%';
            std::cerr.flush();
        }
        std::cerr << std::endl;
    }

    // output stats
    std::cerr << Stats::instance() << std::endl;

    // output image
    std::cout << image << std::endl;
    return 0;
}
<|endoftext|>


<commit_before>/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2017 BMW Car IT GmbH
 * %%
 * 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.
 * #L%
 */
#include <memory>
#include <string>

#include <gtest/gtest.h>
#include <gmock/gmock.h>

#include "joynr/CapabilityUtils.h"
#include "joynr/JoynrClusterControllerRuntime.h"
#include "joynr/LibjoynrSettings.h"
#include "joynr/system/DiscoveryProxy.h"
#include "joynr/Settings.h"
#include "joynr/types/Version.h"
#include "joynr/system/RoutingTypes/MqttAddress.h"
#include "joynr/system/RoutingTypes/ChannelAddress.h"
#include "joynr/serializer/Serializer.h"

#include "tests/JoynrTest.h"
#include "tests/utils/MockObjects.h"

using namespace joynr;

class SystemServicesDiscoveryTest : public ::testing::Test {
public:
    std::string settingsFilename;
    std::unique_ptr<Settings> settings;
    std::string discoveryDomain;
    std::string discoveryProviderParticipantId;
    std::shared_ptr<JoynrClusterControllerRuntime> runtime;
    std::shared_ptr<ITransportMessageReceiver> mockMessageReceiverHttp;
    std::shared_ptr<ITransportMessageReceiver> mockMessageReceiverMqtt;
    std::shared_ptr<ITransportMessageSender> mockMessageSenderMqtt;
    DiscoveryQos discoveryQos;
    std::shared_ptr<ProxyBuilder<joynr::system::DiscoveryProxy>> discoveryProxyBuilder;
    std::shared_ptr<joynr::system::DiscoveryProxy> discoveryProxy;
    std::int64_t lastSeenDateMs;
    std::int64_t expiryDateMs;
    std::string publicKeyId;

    SystemServicesDiscoveryTest() :
        settingsFilename("test-resources/SystemServicesDiscoveryTest.settings"),
        settings(std::make_unique<Settings>(settingsFilename)),
        discoveryDomain(),
        discoveryProviderParticipantId(),
        runtime(),
        mockMessageReceiverHttp(std::make_shared<MockTransportMessageReceiver>()),
        mockMessageReceiverMqtt(std::make_shared<MockTransportMessageReceiver>()),
        mockMessageSenderMqtt(std::make_shared<MockTransportMessageSender>()),
        discoveryQos(),
        discoveryProxyBuilder(nullptr),
        discoveryProxy(nullptr),
        lastSeenDateMs(-1),
        expiryDateMs(-1),
        publicKeyId("")
    {
        SystemServicesSettings systemSettings(*settings);
        systemSettings.printSettings();
        discoveryDomain = systemSettings.getDomain();
        discoveryProviderParticipantId = systemSettings.getCcDiscoveryProviderParticipantId();

        discoveryQos.setCacheMaxAgeMs(1000);
        discoveryQos.setArbitrationStrategy(DiscoveryQos::ArbitrationStrategy::FIXED_PARTICIPANT);
        discoveryQos.addCustomParameter("fixedParticipantId", discoveryProviderParticipantId);
        discoveryQos.setDiscoveryTimeoutMs(50);

        std::string httpChannelId("http_SystemServicesDiscoveryTest.ChannelId");
        std::string httpEndPointUrl("http_SystemServicesRoutingTest.endPointUrl");
        std::string mqttTopic("mqtt_SystemServicesRoutingTest.topic");
        std::string mqttBrokerUrl("mqtt_SystemServicesRoutingTest.brokerUrl");

        using system::RoutingTypes::ChannelAddress;
        using system::RoutingTypes::MqttAddress;

        std::string serializedChannelAddress = joynr::serializer::serializeToJson(ChannelAddress(httpEndPointUrl, httpChannelId));
        std::string serializedMqttAddress = joynr::serializer::serializeToJson(MqttAddress(mqttBrokerUrl, mqttTopic));

        EXPECT_CALL(*(std::dynamic_pointer_cast<MockTransportMessageReceiver>(mockMessageReceiverHttp).get()), getGlobalClusterControllerAddress())
                .WillRepeatedly(::testing::ReturnRefOfCopy(serializedChannelAddress));
        EXPECT_CALL(*(std::dynamic_pointer_cast<MockTransportMessageReceiver>(mockMessageReceiverMqtt)), getGlobalClusterControllerAddress())
                .WillRepeatedly(::testing::ReturnRefOfCopy(serializedMqttAddress));

        //runtime can only be created, after MockCommunicationManager has been told to return
        //a channelId for getReceiveChannelId.
        runtime = std::make_shared<JoynrClusterControllerRuntime>(
                std::move(settings),
                nullptr,
                mockMessageReceiverHttp,
                nullptr,
                mockMessageReceiverMqtt,
                mockMessageSenderMqtt);
        // discovery provider is normally registered in JoynrClusterControllerRuntime::create
        runtime->init();
        discoveryProxyBuilder = runtime->createProxyBuilder<joynr::system::DiscoveryProxy>(discoveryDomain);
    }

    ~SystemServicesDiscoveryTest(){
        discoveryProxy.reset();
        discoveryProxyBuilder.reset();
        runtime->deleteChannel();
        runtime->stopExternalCommunication();
        runtime.reset();

        // Delete persisted files
        std::remove(settingsFilename.c_str());
        std::remove(ClusterControllerSettings::DEFAULT_LOCAL_CAPABILITIES_DIRECTORY_PERSISTENCE_FILENAME().c_str());
        std::remove(LibjoynrSettings::DEFAULT_MESSAGE_ROUTER_PERSISTENCE_FILENAME().c_str());
        std::remove(LibjoynrSettings::DEFAULT_SUBSCRIPTIONREQUEST_PERSISTENCE_FILENAME().c_str());
        std::remove(LibjoynrSettings::DEFAULT_PARTICIPANT_IDS_PERSISTENCE_FILENAME().c_str());
    }

private:
    DISALLOW_COPY_AND_ASSIGN(SystemServicesDiscoveryTest);
};

TEST_F(SystemServicesDiscoveryTest, discoveryProviderIsAvailable)
{
    JOYNR_EXPECT_NO_THROW(
        discoveryProxy = discoveryProxyBuilder
                ->setMessagingQos(MessagingQos(5000))
                ->setDiscoveryQos(discoveryQos)
                ->build();
    );
}

TEST_F(SystemServicesDiscoveryTest, lookupUnknowParticipantReturnsEmptyResult)
{
    discoveryProxy = discoveryProxyBuilder
            ->setMessagingQos(MessagingQos(5000))
            ->setDiscoveryQos(discoveryQos)
            ->build();

    std::vector<joynr::types::DiscoveryEntryWithMetaInfo> result;
    std::string domain("SystemServicesDiscoveryTest.Domain.A");
    std::string interfaceName("SystemServicesDiscoveryTest.InterfaceName.A");
    joynr::types::DiscoveryQos discoveryQos(
                5000,                                     // max cache age
                5000,                                     // discovery ttl
                joynr::types::DiscoveryScope::LOCAL_ONLY, // discovery scope
                false                                     // provider must support on change subscriptions
    );

    try {
        discoveryProxy->lookup(result, {domain}, interfaceName, discoveryQos);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "lookup was not successful";
    }
    EXPECT_TRUE(result.empty());
}

TEST_F(SystemServicesDiscoveryTest, add)
{
    discoveryProxy = discoveryProxyBuilder
            ->setMessagingQos(MessagingQos(5000))
            ->setDiscoveryQos(discoveryQos)
            ->build();

    std::vector<joynr::types::DiscoveryEntryWithMetaInfo> result;
    std::string domain("SystemServicesDiscoveryTest.Domain.A");
    std::string interfaceName("SystemServicesDiscoveryTest.InterfaceName.A");
    std::string participantId("SystemServicesDiscoveryTest.ParticipantID.A");
    joynr::types::DiscoveryQos discoveryQos(
                5000,                                     // max cache age
                5000,                                     // discovery ttl
                joynr::types::DiscoveryScope::LOCAL_ONLY, // discovery scope
                false                                     // provider must support on change subscriptions
    );
    joynr::types::ProviderQos providerQos(
                std::vector<joynr::types::CustomParameter>(), // custom provider parameters
                1,                                      // priority
                joynr::types::ProviderScope::LOCAL,     // scope for provider registration
                false                                   // provider supports on change subscriptions
    );
    joynr::types::Version providerVersion(47, 11);
    joynr::types::DiscoveryEntry discoveryEntry(
                providerVersion,
                domain,
                interfaceName,
                participantId,
                providerQos,
                lastSeenDateMs,
                expiryDateMs,
                publicKeyId
    );
    std::vector<joynr::types::DiscoveryEntryWithMetaInfo> expectedResult;
    auto expectedEntry = util::convert(true, discoveryEntry);
    expectedResult.push_back(expectedEntry);

    try {
        discoveryProxy->lookup(result, {domain}, interfaceName, discoveryQos);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "lookup was not successful";
    }
    EXPECT_TRUE(result.empty());

    try {
        discoveryProxy->add(discoveryEntry);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "add was not successful";
    }

    try {
        discoveryProxy->lookup(result, {domain}, interfaceName, discoveryQos);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "lookup was not successful";
    }
    EXPECT_EQ(expectedResult, result);
}

TEST_F(SystemServicesDiscoveryTest, remove)
{
    discoveryProxy = discoveryProxyBuilder
            ->setMessagingQos(MessagingQos(5000))
            ->setDiscoveryQos(discoveryQos)
            ->build();

    std::string domain("SystemServicesDiscoveryTest.Domain.A");
    std::string interfaceName("SystemServicesDiscoveryTest.InterfaceName.A");
    std::string participantId("SystemServicesDiscoveryTest.ParticipantID.A");
    joynr::types::DiscoveryQos discoveryQos(
                5000,                                     // max cache age
                5000,                                     // discovery ttl
                joynr::types::DiscoveryScope::LOCAL_ONLY, // discovery scope
                false                                     // provider must support on change subscriptions
    );
    joynr::types::ProviderQos providerQos(
                std::vector<joynr::types::CustomParameter>(), // custom provider parameters
                1,                                      // priority
                joynr::types::ProviderScope::LOCAL,     // scope for provider registration
                false                                   // provider supports on change subscriptions
    );
    joynr::types::Version providerVersion(47, 11);
    joynr::types::DiscoveryEntry discoveryEntry(
                providerVersion,
                domain,
                interfaceName,
                participantId,
                providerQos,
                lastSeenDateMs,
                expiryDateMs,
                publicKeyId
    );

    std::vector<joynr::types::DiscoveryEntryWithMetaInfo> expectedResult;
    auto expectedEntry = util::convert(true, discoveryEntry);
    expectedResult.push_back(expectedEntry);

    try {
        discoveryProxy->add(discoveryEntry);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "add was not successful";
    }

    std::vector<joynr::types::DiscoveryEntryWithMetaInfo> result;
    try {
        discoveryProxy->lookup(result, {domain}, interfaceName, discoveryQos);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "lookup was not successful";
    }
    EXPECT_EQ(expectedResult, result);

    try {
        discoveryProxy->remove(participantId);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "remove was not successful";
    }

    result.clear();
    try {
        discoveryProxy->lookup(result, {domain}, interfaceName, discoveryQos);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "lookup was not successful";
    }
    EXPECT_TRUE(result.empty());
}
<commit_msg>[C++] Stabilize SystemServicesDiscoveryTest<commit_after>/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2017 BMW Car IT GmbH
 * %%
 * 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.
 * #L%
 */
#include <memory>
#include <string>

#include <gtest/gtest.h>
#include <gmock/gmock.h>

#include "joynr/CapabilityUtils.h"
#include "joynr/JoynrClusterControllerRuntime.h"
#include "joynr/LibjoynrSettings.h"
#include "joynr/system/DiscoveryProxy.h"
#include "joynr/Settings.h"
#include "joynr/types/Version.h"
#include "joynr/system/RoutingTypes/MqttAddress.h"
#include "joynr/system/RoutingTypes/ChannelAddress.h"
#include "joynr/serializer/Serializer.h"

#include "tests/JoynrTest.h"
#include "tests/utils/MockObjects.h"

using namespace joynr;

class SystemServicesDiscoveryTest : public ::testing::Test {
public:
    std::string settingsFilename;
    std::unique_ptr<Settings> settings;
    std::string discoveryDomain;
    std::string discoveryProviderParticipantId;
    std::shared_ptr<JoynrClusterControllerRuntime> runtime;
    std::shared_ptr<ITransportMessageReceiver> mockMessageReceiverHttp;
    std::shared_ptr<ITransportMessageReceiver> mockMessageReceiverMqtt;
    std::shared_ptr<ITransportMessageSender> mockMessageSenderMqtt;
    DiscoveryQos discoveryQos;
    std::shared_ptr<ProxyBuilder<joynr::system::DiscoveryProxy>> discoveryProxyBuilder;
    std::shared_ptr<joynr::system::DiscoveryProxy> discoveryProxy;
    std::int64_t lastSeenDateMs;
    std::int64_t expiryDateMs;
    std::string publicKeyId;

    SystemServicesDiscoveryTest() :
        settingsFilename("test-resources/SystemServicesDiscoveryTest.settings"),
        settings(std::make_unique<Settings>(settingsFilename)),
        discoveryDomain(),
        discoveryProviderParticipantId(),
        runtime(),
        mockMessageReceiverHttp(std::make_shared<MockTransportMessageReceiver>()),
        mockMessageReceiverMqtt(std::make_shared<MockTransportMessageReceiver>()),
        mockMessageSenderMqtt(std::make_shared<MockTransportMessageSender>()),
        discoveryQos(),
        discoveryProxyBuilder(nullptr),
        discoveryProxy(nullptr),
        lastSeenDateMs(-1),
        expiryDateMs(-1),
        publicKeyId("")
    {
        SystemServicesSettings systemSettings(*settings);
        systemSettings.printSettings();
        discoveryDomain = systemSettings.getDomain();
        discoveryProviderParticipantId = systemSettings.getCcDiscoveryProviderParticipantId();

        discoveryQos.setCacheMaxAgeMs(1000);
        discoveryQos.setArbitrationStrategy(DiscoveryQos::ArbitrationStrategy::FIXED_PARTICIPANT);
        discoveryQos.addCustomParameter("fixedParticipantId", discoveryProviderParticipantId);
        discoveryQos.setDiscoveryTimeoutMs(50);

        std::string httpChannelId("http_SystemServicesDiscoveryTest.ChannelId");
        std::string httpEndPointUrl("http_SystemServicesRoutingTest.endPointUrl");
        std::string mqttTopic("mqtt_SystemServicesRoutingTest.topic");
        std::string mqttBrokerUrl("mqtt_SystemServicesRoutingTest.brokerUrl");

        using system::RoutingTypes::ChannelAddress;
        using system::RoutingTypes::MqttAddress;

        std::string serializedChannelAddress = joynr::serializer::serializeToJson(ChannelAddress(httpEndPointUrl, httpChannelId));
        std::string serializedMqttAddress = joynr::serializer::serializeToJson(MqttAddress(mqttBrokerUrl, mqttTopic));

        EXPECT_CALL(*(std::dynamic_pointer_cast<MockTransportMessageReceiver>(mockMessageReceiverHttp).get()), getGlobalClusterControllerAddress())
                .WillRepeatedly(::testing::ReturnRefOfCopy(serializedChannelAddress));
        EXPECT_CALL(*(std::dynamic_pointer_cast<MockTransportMessageReceiver>(mockMessageReceiverMqtt)), getGlobalClusterControllerAddress())
                .WillRepeatedly(::testing::ReturnRefOfCopy(serializedMqttAddress));

        //runtime can only be created, after MockCommunicationManager has been told to return
        //a channelId for getReceiveChannelId.
        runtime = std::make_shared<JoynrClusterControllerRuntime>(
                std::move(settings),
                nullptr,
                mockMessageReceiverHttp,
                nullptr,
                mockMessageReceiverMqtt,
                mockMessageSenderMqtt);
        // discovery provider is normally registered in JoynrClusterControllerRuntime::create
        runtime->init();
        discoveryProxyBuilder = runtime->createProxyBuilder<joynr::system::DiscoveryProxy>(discoveryDomain);
    }

    ~SystemServicesDiscoveryTest(){
        discoveryProxy.reset();
        discoveryProxyBuilder.reset();
        runtime->deleteChannel();
        runtime->stopExternalCommunication();
        runtime.reset();

        // Delete persisted files
        std::remove(settingsFilename.c_str());
        std::remove(ClusterControllerSettings::DEFAULT_LOCAL_CAPABILITIES_DIRECTORY_PERSISTENCE_FILENAME().c_str());
        std::remove(LibjoynrSettings::DEFAULT_MESSAGE_ROUTER_PERSISTENCE_FILENAME().c_str());
        std::remove(LibjoynrSettings::DEFAULT_SUBSCRIPTIONREQUEST_PERSISTENCE_FILENAME().c_str());
        std::remove(LibjoynrSettings::DEFAULT_PARTICIPANT_IDS_PERSISTENCE_FILENAME().c_str());
    }

private:
    DISALLOW_COPY_AND_ASSIGN(SystemServicesDiscoveryTest);
};

TEST_F(SystemServicesDiscoveryTest, discoveryProviderIsAvailable)
{
    JOYNR_EXPECT_NO_THROW(
        discoveryProxy = discoveryProxyBuilder
                ->setMessagingQos(MessagingQos(5000))
                ->setDiscoveryQos(discoveryQos)
                ->build();
    );
}

TEST_F(SystemServicesDiscoveryTest, lookupUnknowParticipantReturnsEmptyResult)
{
    discoveryProxy = discoveryProxyBuilder
            ->setMessagingQos(MessagingQos(5000))
            ->setDiscoveryQos(discoveryQos)
            ->build();

    std::vector<joynr::types::DiscoveryEntryWithMetaInfo> result;
    std::string domain("SystemServicesDiscoveryTest.Domain.A");
    std::string interfaceName("SystemServicesDiscoveryTest.InterfaceName.A");
    joynr::types::DiscoveryQos discoveryQos(
                5000,                                     // max cache age
                5000,                                     // discovery ttl
                joynr::types::DiscoveryScope::LOCAL_ONLY, // discovery scope
                false                                     // provider must support on change subscriptions
    );

    try {
        discoveryProxy->lookup(result, {domain}, interfaceName, discoveryQos);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "lookup was not successful";
    }
    EXPECT_TRUE(result.empty());
}

TEST_F(SystemServicesDiscoveryTest, add)
{
    discoveryProxy = discoveryProxyBuilder
            ->setMessagingQos(MessagingQos(5000))
            ->setDiscoveryQos(discoveryQos)
            ->build();

    std::vector<joynr::types::DiscoveryEntryWithMetaInfo> result;
    std::string domain("SystemServicesDiscoveryTest.Domain.A");
    std::string interfaceName("SystemServicesDiscoveryTest.InterfaceName.A");
    std::string participantId("SystemServicesDiscoveryTest.ParticipantID.A");
    joynr::types::DiscoveryQos discoveryQos(
                5000,                                     // max cache age
                5000,                                     // discovery ttl
                joynr::types::DiscoveryScope::LOCAL_ONLY, // discovery scope
                false                                     // provider must support on change subscriptions
    );
    joynr::types::ProviderQos providerQos(
                std::vector<joynr::types::CustomParameter>(), // custom provider parameters
                1,                                      // priority
                joynr::types::ProviderScope::LOCAL,     // scope for provider registration
                false                                   // provider supports on change subscriptions
    );
    joynr::types::Version providerVersion(47, 11);
    joynr::types::DiscoveryEntry discoveryEntry(
                providerVersion,
                domain,
                interfaceName,
                participantId,
                providerQos,
                lastSeenDateMs,
                expiryDateMs,
                publicKeyId
    );
    std::vector<joynr::types::DiscoveryEntryWithMetaInfo> expectedResult;
    auto expectedEntry = util::convert(true, discoveryEntry);
    expectedResult.push_back(expectedEntry);

    try {
        discoveryProxy->lookup(result, {domain}, interfaceName, discoveryQos);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "lookup was not successful";
    }
    EXPECT_TRUE(result.empty());

    try {
        discoveryProxy->add(discoveryEntry);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "add was not successful";
    }

    try {
        discoveryProxy->lookup(result, {domain}, interfaceName, discoveryQos);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "lookup was not successful";
    }
    EXPECT_EQ(expectedResult, result);

    // cleanup after test
    try {
        discoveryProxy->remove(participantId);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "remove was not successful";
    }
}

TEST_F(SystemServicesDiscoveryTest, remove)
{
    discoveryProxy = discoveryProxyBuilder
            ->setMessagingQos(MessagingQos(5000))
            ->setDiscoveryQos(discoveryQos)
            ->build();

    std::string domain("SystemServicesDiscoveryTest.Domain.A");
    std::string interfaceName("SystemServicesDiscoveryTest.InterfaceName.A");
    std::string participantId("SystemServicesDiscoveryTest.ParticipantID.A");
    joynr::types::DiscoveryQos discoveryQos(
                5000,                                     // max cache age
                5000,                                     // discovery ttl
                joynr::types::DiscoveryScope::LOCAL_ONLY, // discovery scope
                false                                     // provider must support on change subscriptions
    );
    joynr::types::ProviderQos providerQos(
                std::vector<joynr::types::CustomParameter>(), // custom provider parameters
                1,                                      // priority
                joynr::types::ProviderScope::LOCAL,     // scope for provider registration
                false                                   // provider supports on change subscriptions
    );
    joynr::types::Version providerVersion(47, 11);
    joynr::types::DiscoveryEntry discoveryEntry(
                providerVersion,
                domain,
                interfaceName,
                participantId,
                providerQos,
                lastSeenDateMs,
                expiryDateMs,
                publicKeyId
    );

    std::vector<joynr::types::DiscoveryEntryWithMetaInfo> expectedResult;
    auto expectedEntry = util::convert(true, discoveryEntry);
    expectedResult.push_back(expectedEntry);

    try {
        discoveryProxy->add(discoveryEntry);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "add was not successful";
    }

    std::vector<joynr::types::DiscoveryEntryWithMetaInfo> result;
    try {
        discoveryProxy->lookup(result, {domain}, interfaceName, discoveryQos);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "lookup was not successful";
    }
    EXPECT_EQ(expectedResult, result);

    try {
        discoveryProxy->remove(participantId);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "remove was not successful";
    }

    result.clear();
    try {
        discoveryProxy->lookup(result, {domain}, interfaceName, discoveryQos);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "lookup was not successful";
    }
    EXPECT_TRUE(result.empty());
}
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 *             Copyright (c) 2009 Sony Pictures Imageworks, Inc.
 *                            All rights reserved.
 *
 *  This material contains the confidential and proprietary information
 *  of Sony Pictures Imageworks, Inc. and may not be disclosed, copied or
 *  duplicated in any form, electronic or hardcopy, in whole or in part,
 *  without the express prior written consent of Sony Pictures Imageworks,
 *  Inc. This copyright notice does not imply publication.
 *
 *****************************************************************************/

#include <vector>
#include <string>
#include <cstdio>

#include "boost/foreach.hpp"

#include "OpenImageIO/dassert.h"
#include "OpenImageIO/thread.h"

#include "oslexec_pvt.h"

namespace {
// Define static ustring symbols for very fast comparison
static ustring P_("P"), I_("I"), N_("N"), Ng_("Ng");
static ustring dPdu_("dPdu"), dPdv_("dPdv"), u_("u"), v_("v");
static ustring time_("time"), dtime_("dtime"), dPdtime_("dPdtime");
};

namespace OSL {
namespace pvt {   // OSL::pvt

ShadingExecution::ShadingExecution ()
    : m_context(NULL), m_instance(NULL), m_master(NULL),
      m_bound(false), m_debug(false)
{
}

ShadingExecution::~ShadingExecution ()
{
}

void
ShadingExecution::bind (ShadingContext *context, ShaderUse use,
                        int layerindex, ShaderInstance *instance)
{
    ASSERT (! m_bound);  // avoid double-binding
    ASSERT (context != NULL && instance != NULL);

    m_debug = context->shadingsys().debug();
    if (m_debug)
        std::cout << "bind ctx " << (void *)context << " use "
                  << shaderusename(use) << " layer " << layerindex << "\n";
    m_use = use;

    // Take various shortcuts if we are re-binding the same instance as
    // last time.
    bool rebind = (m_context == context && m_instance == instance);
    if (! rebind) {
        m_context = context;
        m_instance = instance;
        m_master = instance->master ();
        ASSERT (m_master);
    }

    m_npoints = m_context->npoints ();
    m_symbols = m_instance->m_symbols;  // fresh copy of symbols from instance
    ShaderGlobals *globals (m_context->m_globals);

    // FIXME: bind the symbols -- get the syms ready and pointing to the
    // right place in the heap,, interpolate primitive variables, handle
    // connections, initialize all parameters
    BOOST_FOREACH (Symbol &sym, m_symbols) {
        if (m_debug)
            std::cout << "  bind " << sym.mangled()
                      << ", offset " << sym.dataoffset() << "\n";
        if (sym.symtype() == SymTypeGlobal) {
            // FIXME -- is this too wasteful here?
            if (sym.name() == P_) {
                sym.data (globals->P.ptr());  sym.step (globals->P.step());
            } else if (sym.name() == I_) {
                sym.data (globals->I.ptr());  sym.step (globals->I.step());
            } else if (sym.name() == N_) {
                sym.data (globals->N.ptr());  sym.step (globals->N.step());
            } else if (sym.name() == Ng_) {
                sym.data (globals->Ng.ptr());  sym.step (globals->Ng.step());
            } else if (sym.name() == u_) {
                sym.data (globals->u.ptr());  sym.step (globals->u.step());
            } else if (sym.name() == v_) {
                sym.data (globals->v.ptr());  sym.step (globals->v.step());
            } else if (sym.name() == dPdu_) {
                sym.data (globals->dPdu.ptr());  sym.step (globals->dPdu.step());
            } else if (sym.name() == dPdv_) {
                sym.data (globals->dPdv.ptr());  sym.step (globals->dPdv.step());
            } else if (sym.name() == time_) {
                sym.data (globals->time.ptr());  sym.step (globals->time.step());
            } else if (sym.name() == dtime_) {
                sym.data (globals->dtime.ptr());  sym.step (globals->dtime.step());
            } else if (sym.name() == dPdtime_) {
                sym.data (globals->dPdtime.ptr());  sym.step (globals->dPdtime.step());
            }
            if (sym.data() == NULL) {
                if (sym.dataoffset() >= 0) {
                    // Not specified where it lives, put it in the heap
                    sym.data (m_context->heapaddr (sym.dataoffset()));
                    sym.step (0);
                    std::cout << "Global " << sym.name() << " at address " << sym.dataoffset() << "\n";
                } else {
                    // ASSERT (sym.dataoffset() >= 0 &&
                    //         "Global ought to already have a dataoffset");
                    // Skip this for now -- it includes L, Cl, etc.
                    sym.step (0);   // FIXME
                }
            }
        } else if (sym.symtype() == SymTypeParam ||
                   sym.symtype() == SymTypeOutputParam) {
//            ASSERT (sym.dataoffset() < 0 &&
//                    "Param should not yet have a data offset");
//            sym.dataoffset (m_context->heap_allot (sym.typespec().simpletype().size()));
            size_t addr = context->heap_allot (sym.typespec().simpletype().size());
            sym.data (m_context->heapaddr (addr));
            sym.step (0);  // FIXME
            // Copy the parameter value
            // FIXME -- if the parameter is not being overridden and is
            // not writeable, I think we should just point to the parameter
            // data, not copy it?  Or does it matter?
            if (sym.typespec().simpletype().basetype == TypeDesc::FLOAT)
                memcpy (sym.data(), &instance->m_fparams[sym.dataoffset()],
                        sym.typespec().simpletype().size());
            else if (sym.typespec().simpletype().basetype == TypeDesc::INT)
                memcpy (sym.data(), &instance->m_iparams[sym.dataoffset()],
                        sym.typespec().simpletype().size());
            else if (sym.typespec().simpletype().basetype == TypeDesc::STRING)
                memcpy (sym.data(), &instance->m_sparams[sym.dataoffset()],
                        sym.typespec().simpletype().size());
        } else if (sym.symtype() == SymTypeLocal ||
                   sym.symtype() == SymTypeTemp) {
            ASSERT (sym.dataoffset() < 0);
            sym.dataoffset (m_context->heap_allot (sym.typespec().simpletype().size()));
            sym.data (m_context->heapaddr (sym.dataoffset()));
            sym.step (0);  // FIXME
        } else if (sym.symtype() == SymTypeConst) {
            ASSERT (sym.data() != NULL &&
                    "Const symbol should already have valid data address");
        } else {
            ASSERT (0 && "Should never get here");
        }
        if (m_debug)
            std::cout << "  bound " << sym.mangled() << " to address "
                      << (void *)sym.data() << ", step " << sym.step()
                      << ", size " << sym.size() << "\n";
    }

    m_bound = true;
    m_executed = false;
}

void
ShadingExecution::run (Runflag *rf)
{
    if (m_executed)
        return;       // Already executed

    if (m_debug)
        std::cout << "Running ShadeExec " << (void *)this << ", shader "
                  << m_master->shadername() << "\n";

    ASSERT (m_bound);  // We'd better be bound at this point

    // Make space for new runflags
    m_runflags = (Runflag *) alloca (m_npoints * sizeof(Runflag));
    if (rf) {
        // Passed runflags -- copy those
        memcpy (m_runflags, rf, m_npoints*sizeof(Runflag));
        new_runflag_range (0, m_npoints);
    } else {
        // If not passed runflags, make new ones
        for (int i = 0;  i < m_npoints;  ++i)
            m_runflags[i] = 1;
        m_beginpoint = 0;
        m_endpoint = m_npoints;
        m_all_points_on = true;
    }

    // FIXME -- push the runflags, begin, end

    // FIXME -- this runs every op.  Really, we just want the main code body.
    run (0, (int)m_master->m_ops.size());

    // FIXME -- pop the runflags, begin, end

    m_executed = true;
}

void
ShadingExecution::run (int beginop, int endop)
{
    if (m_debug)
        std::cout << "Running ShadeExec " << (void *)this
                  << ", shader " << m_master->shadername()
                  << " ops [" << beginop << "," << endop << ")\n";
    const int *args = &m_master->m_args[0];
    for (m_ip = beginop; m_ip < endop && m_beginpoint < m_endpoint;  ++m_ip) {
        Opcode &op (this->op ());
        if (m_debug) {
            std::cout << "  instruction " << m_ip << ": " << op.opname() << " ";
        }
        for (int i = 0;  i < op.nargs();  ++i) {
            int arg = args[op.firstarg()+i];
            if (m_debug)
                std::cout << sym(arg).mangled() << " ";
        }
        if (m_debug)
            std::cout << "\n";
        ASSERT (op.implementation() && "Unimplemented op!");
        op (this, op.nargs(), args+op.firstarg(),
            m_runflags, m_beginpoint, m_endpoint);

        // FIXME -- this is a good place to do all sorts of other sanity
        // checks, like seeing if any nans have crept in from each op.

        if (m_debug) {
            std::cout << "After running '" << op.opname()
                      << "', new values are:\n";
            for (int i = 0;  i < op.nargs();  ++i) {
                Symbol &s (sym (args[op.firstarg()+i]));
                std::cout << "    " << s.mangled() << "\n";
                printsymbol (s);
            }
        }
    }
}

void
ShadingExecution::adjust_varying (Symbol &sym, bool varying_assignment,
                                  bool preserve_value)
{
    // This is tricky.  To make sure we're catching all the cases, let's
    // enumerate them by the current symbol varyingness, the assignent
    // varyingness, and whether all points in the grid are active:
    //   case   sym    assignment   all_pts_on     action
    //    0      v         v            n           v (leave alone)
    //    1      v         v            y           v (leave alone)
    //    2      v         u            n           v (leave alone)
    //    3      v         u            y           u (demote)
    //    4      u         v            n           v (promote)
    //    5      u         v            y           v (promote)
    //    6      u         u            n           v (promote)
    //    7      u         u            y           u (leave alone)

    // If we're inside a conditional of any kind, even a uniform assignment
    // makes the result varying.
    varying_assignment |= ! all_points_on();

    // This reduces us to just four cases:
    //   case   sym    assignment   action
    //    0/1/2  v         v          v (leave alone)
    //    3      v         u          u (demote)
    //    4/5/6  u         v          v (promote)
    //    7      u         u          u (leave alone)

    // Trivial case: we need it varying and it already is, or we need it
    // uniform and it already is.
    if (sym.is_varying() == varying_assignment)
        return;

    if (varying_assignment) {
        // sym is uniform, but we're either assigning a new varying
        // value or we're inside a conditional.  Promote sym to varying.
        sym.step (sym.size());
        if (preserve_value || ! all_points_on()) {
            // Propagate the value from slot 0 to other slots
            size_t size = sym.size();
            char *data = (char *) sym.data();
            for (int i = 1;  i < m_npoints;  ++i)
                memcpy (data + i*size, data, size);
        }
    } else {
        // sym is varying, but we're assigning a new uniform value AND
        // we're not inside a conditional.  Safe to demote sym to uniform.
        if (sym.symtype() != SymTypeGlobal) // DO NOT demote a global
            sym.step (0);
    }
}

void
ShadingExecution::new_runflag_range (int begin, int end)
{
    m_beginpoint = INT_MAX;
    m_endpoint = -1;
    m_all_points_on = (begin == 0 && end == m_npoints);
    for (int i = begin;  i < end;  ++i) {
        if (m_runflags[i]) {
            if (i < m_beginpoint)
                m_beginpoint = i;
            if (i >= m_endpoint)
                m_endpoint = i+1;
        } else {
            m_all_points_on = false;
        }
    }
}

void
ShadingExecution::printsymbol (Symbol &sym)
{
    const char *data = (const char *) sym.data ();
    TypeDesc type = sym.typespec().simpletype();
    data += m_beginpoint * sym.step();
    for (int i = m_beginpoint;  i < m_endpoint;  ++i, data += sym.step()) {
        if (sym.is_uniform())
            std::cout << "\tuniform";
        else if (i == m_beginpoint || (i%8) == 0)
            std::cout << "\t" << i << ":";
        int n = type.numelements() * type.aggregate;
        for (int j = 0;  j < n;  ++j) {
            std::cout << ' ';
            if (type.basetype == TypeDesc::FLOAT)
                std::cout << ((float *)data)[j];
            else if (type.basetype == TypeDesc::INT)
                std::cout << ((int *)data)[j];
            else if (type.basetype == TypeDesc::STRING)
                std::cout << ((ustring *)data)[j];
        }
        if (i == m_endpoint-1 || (i%8) == 7 || sym.is_uniform())
            std::cout << "\n";
        if (sym.is_uniform())
            break;
    }
}

}; // namespace pvt
}; // namespace OSL
<commit_msg>Bug fix -- was not multiplying heap allocation sizes by npoints!<commit_after>/*****************************************************************************
 *
 *             Copyright (c) 2009 Sony Pictures Imageworks, Inc.
 *                            All rights reserved.
 *
 *  This material contains the confidential and proprietary information
 *  of Sony Pictures Imageworks, Inc. and may not be disclosed, copied or
 *  duplicated in any form, electronic or hardcopy, in whole or in part,
 *  without the express prior written consent of Sony Pictures Imageworks,
 *  Inc. This copyright notice does not imply publication.
 *
 *****************************************************************************/

#include <vector>
#include <string>
#include <cstdio>

#include "boost/foreach.hpp"

#include "OpenImageIO/dassert.h"
#include "OpenImageIO/thread.h"

#include "oslexec_pvt.h"

namespace {
// Define static ustring symbols for very fast comparison
static ustring P_("P"), I_("I"), N_("N"), Ng_("Ng");
static ustring dPdu_("dPdu"), dPdv_("dPdv"), u_("u"), v_("v");
static ustring time_("time"), dtime_("dtime"), dPdtime_("dPdtime");
};

namespace OSL {
namespace pvt {   // OSL::pvt

ShadingExecution::ShadingExecution ()
    : m_context(NULL), m_instance(NULL), m_master(NULL),
      m_bound(false), m_debug(false)
{
}

ShadingExecution::~ShadingExecution ()
{
}

void
ShadingExecution::bind (ShadingContext *context, ShaderUse use,
                        int layerindex, ShaderInstance *instance)
{
    ASSERT (! m_bound);  // avoid double-binding
    ASSERT (context != NULL && instance != NULL);

    m_debug = context->shadingsys().debug();
    if (m_debug)
        std::cout << "bind ctx " << (void *)context << " use "
                  << shaderusename(use) << " layer " << layerindex << "\n";
    m_use = use;

    // Take various shortcuts if we are re-binding the same instance as
    // last time.
    bool rebind = (m_context == context && m_instance == instance);
    if (! rebind) {
        m_context = context;
        m_instance = instance;
        m_master = instance->master ();
        ASSERT (m_master);
    }

    m_npoints = m_context->npoints ();
    m_symbols = m_instance->m_symbols;  // fresh copy of symbols from instance
    ShaderGlobals *globals (m_context->m_globals);

    // FIXME: bind the symbols -- get the syms ready and pointing to the
    // right place in the heap,, interpolate primitive variables, handle
    // connections, initialize all parameters
    BOOST_FOREACH (Symbol &sym, m_symbols) {
        if (m_debug)
            std::cout << "  bind " << sym.mangled()
                      << ", offset " << sym.dataoffset() << "\n";
        if (sym.symtype() == SymTypeGlobal) {
            // FIXME -- is this too wasteful here?
            if (sym.name() == P_) {
                sym.data (globals->P.ptr());  sym.step (globals->P.step());
            } else if (sym.name() == I_) {
                sym.data (globals->I.ptr());  sym.step (globals->I.step());
            } else if (sym.name() == N_) {
                sym.data (globals->N.ptr());  sym.step (globals->N.step());
            } else if (sym.name() == Ng_) {
                sym.data (globals->Ng.ptr());  sym.step (globals->Ng.step());
            } else if (sym.name() == u_) {
                sym.data (globals->u.ptr());  sym.step (globals->u.step());
            } else if (sym.name() == v_) {
                sym.data (globals->v.ptr());  sym.step (globals->v.step());
            } else if (sym.name() == dPdu_) {
                sym.data (globals->dPdu.ptr());  sym.step (globals->dPdu.step());
            } else if (sym.name() == dPdv_) {
                sym.data (globals->dPdv.ptr());  sym.step (globals->dPdv.step());
            } else if (sym.name() == time_) {
                sym.data (globals->time.ptr());  sym.step (globals->time.step());
            } else if (sym.name() == dtime_) {
                sym.data (globals->dtime.ptr());  sym.step (globals->dtime.step());
            } else if (sym.name() == dPdtime_) {
                sym.data (globals->dPdtime.ptr());  sym.step (globals->dPdtime.step());
            }
            if (sym.data() == NULL) {
                if (sym.dataoffset() >= 0) {
                    // Not specified where it lives, put it in the heap
                    sym.data (m_context->heapaddr (sym.dataoffset()));
                    sym.step (0);
                    std::cout << "Global " << sym.name() << " at address " << sym.dataoffset() << "\n";
                } else {
                    // ASSERT (sym.dataoffset() >= 0 &&
                    //         "Global ought to already have a dataoffset");
                    // Skip this for now -- it includes L, Cl, etc.
                    sym.step (0);   // FIXME
                }
            }
        } else if (sym.symtype() == SymTypeParam ||
                   sym.symtype() == SymTypeOutputParam) {
//            ASSERT (sym.dataoffset() < 0 &&
//                    "Param should not yet have a data offset");
//            sym.dataoffset (m_context->heap_allot (sym.typespec().simpletype().size()) * m_npoints);
            size_t addr = context->heap_allot (sym.typespec().simpletype().size() * m_npoints);
            sym.data (m_context->heapaddr (addr));
            sym.step (0);  // FIXME
            // Copy the parameter value
            // FIXME -- if the parameter is not being overridden and is
            // not writeable, I think we should just point to the parameter
            // data, not copy it?  Or does it matter?
            if (sym.typespec().simpletype().basetype == TypeDesc::FLOAT)
                memcpy (sym.data(), &instance->m_fparams[sym.dataoffset()],
                        sym.typespec().simpletype().size());
            else if (sym.typespec().simpletype().basetype == TypeDesc::INT)
                memcpy (sym.data(), &instance->m_iparams[sym.dataoffset()],
                        sym.typespec().simpletype().size());
            else if (sym.typespec().simpletype().basetype == TypeDesc::STRING)
                memcpy (sym.data(), &instance->m_sparams[sym.dataoffset()],
                        sym.typespec().simpletype().size());
        } else if (sym.symtype() == SymTypeLocal ||
                   sym.symtype() == SymTypeTemp) {
            ASSERT (sym.dataoffset() < 0);
            sym.dataoffset (m_context->heap_allot (sym.typespec().simpletype().size()) * m_npoints);
            sym.data (m_context->heapaddr (sym.dataoffset()));
            sym.step (0);  // FIXME
        } else if (sym.symtype() == SymTypeConst) {
            ASSERT (sym.data() != NULL &&
                    "Const symbol should already have valid data address");
        } else {
            ASSERT (0 && "Should never get here");
        }
        if (m_debug)
            std::cout << "  bound " << sym.mangled() << " to address "
                      << (void *)sym.data() << ", step " << sym.step()
                      << ", size " << sym.size() << "\n";
    }

    m_bound = true;
    m_executed = false;
}

void
ShadingExecution::run (Runflag *rf)
{
    if (m_executed)
        return;       // Already executed

    if (m_debug)
        std::cout << "Running ShadeExec " << (void *)this << ", shader "
                  << m_master->shadername() << "\n";

    ASSERT (m_bound);  // We'd better be bound at this point

    // Make space for new runflags
    m_runflags = (Runflag *) alloca (m_npoints * sizeof(Runflag));
    if (rf) {
        // Passed runflags -- copy those
        memcpy (m_runflags, rf, m_npoints*sizeof(Runflag));
        new_runflag_range (0, m_npoints);
    } else {
        // If not passed runflags, make new ones
        for (int i = 0;  i < m_npoints;  ++i)
            m_runflags[i] = 1;
        m_beginpoint = 0;
        m_endpoint = m_npoints;
        m_all_points_on = true;
    }

    // FIXME -- push the runflags, begin, end

    // FIXME -- this runs every op.  Really, we just want the main code body.
    run (0, (int)m_master->m_ops.size());

    // FIXME -- pop the runflags, begin, end

    m_executed = true;
}

void
ShadingExecution::run (int beginop, int endop)
{
    if (m_debug)
        std::cout << "Running ShadeExec " << (void *)this
                  << ", shader " << m_master->shadername()
                  << " ops [" << beginop << "," << endop << ")\n";
    const int *args = &m_master->m_args[0];
    for (m_ip = beginop; m_ip < endop && m_beginpoint < m_endpoint;  ++m_ip) {
        Opcode &op (this->op ());
        if (m_debug) {
            std::cout << "instruction " << m_ip << ": " << op.opname() << " ";
        }
        if (m_debug) {
            std::cout << "Before running '" << op.opname()
                      << "', values are:\n";
            for (int i = 0;  i < op.nargs();  ++i) {
                Symbol &s (sym (args[op.firstarg()+i]));
                std::cout << "    " << s.mangled() << "\n";
                printsymbol (s);
            }
        }
        for (int i = 0;  i < op.nargs();  ++i) {
            int arg = args[op.firstarg()+i];
            if (m_debug)
                std::cout << sym(arg).mangled() << " ";
        }
        if (m_debug)
            std::cout << "\n";
        ASSERT (op.implementation() && "Unimplemented op!");
        op (this, op.nargs(), args+op.firstarg(),
            m_runflags, m_beginpoint, m_endpoint);

        // FIXME -- this is a good place to do all sorts of other sanity
        // checks, like seeing if any nans have crept in from each op.

        if (m_debug) {
            std::cout << "After running '" << op.opname()
                      << "', new values are:\n";
            for (int i = 0;  i < op.nargs();  ++i) {
                Symbol &s (sym (args[op.firstarg()+i]));
                std::cout << "    " << s.mangled() << "\n";
                printsymbol (s);
            }
        }
    }
}

void
ShadingExecution::adjust_varying (Symbol &sym, bool varying_assignment,
                                  bool preserve_value)
{
    // This is tricky.  To make sure we're catching all the cases, let's
    // enumerate them by the current symbol varyingness, the assignent
    // varyingness, and whether all points in the grid are active:
    //   case   sym    assignment   all_pts_on     action
    //    0      v         v            n           v (leave alone)
    //    1      v         v            y           v (leave alone)
    //    2      v         u            n           v (leave alone)
    //    3      v         u            y           u (demote)
    //    4      u         v            n           v (promote)
    //    5      u         v            y           v (promote)
    //    6      u         u            n           v (promote)
    //    7      u         u            y           u (leave alone)

    // If we're inside a conditional of any kind, even a uniform assignment
    // makes the result varying.
    varying_assignment |= ! all_points_on();

    // This reduces us to just four cases:
    //   case   sym    assignment   action
    //    0/1/2  v         v          v (leave alone)
    //    3      v         u          u (demote)
    //    4/5/6  u         v          v (promote)
    //    7      u         u          u (leave alone)

    // Trivial case: we need it varying and it already is, or we need it
    // uniform and it already is.
    if (sym.is_varying() == varying_assignment)
        return;

    if (varying_assignment) {
        // sym is uniform, but we're either assigning a new varying
        // value or we're inside a conditional.  Promote sym to varying.
        sym.step (sym.size());
        if (preserve_value || ! all_points_on()) {
            // Propagate the value from slot 0 to other slots
            size_t size = sym.size();
            char *data = (char *) sym.data();
            for (int i = 1;  i < m_npoints;  ++i)
                memcpy (data + i*size, data, size);
        }
    } else {
        // sym is varying, but we're assigning a new uniform value AND
        // we're not inside a conditional.  Safe to demote sym to uniform.
        if (sym.symtype() != SymTypeGlobal) // DO NOT demote a global
            sym.step (0);
    }
}

void
ShadingExecution::new_runflag_range (int begin, int end)
{
    m_beginpoint = INT_MAX;
    m_endpoint = -1;
    m_all_points_on = (begin == 0 && end == m_npoints);
    for (int i = begin;  i < end;  ++i) {
        if (m_runflags[i]) {
            if (i < m_beginpoint)
                m_beginpoint = i;
            if (i >= m_endpoint)
                m_endpoint = i+1;
        } else {
            m_all_points_on = false;
        }
    }
}

void
ShadingExecution::printsymbol (Symbol &sym)
{
    const char *data = (const char *) sym.data ();
    TypeDesc type = sym.typespec().simpletype();
    data += m_beginpoint * sym.step();
    for (int i = m_beginpoint;  i < m_endpoint;  ++i, data += sym.step()) {
        if (sym.is_uniform())
            std::cout << "\tuniform";
        else if (i == m_beginpoint || (i%8) == 0)
            std::cout << "\t" << i << ":";
        int n = type.numelements() * type.aggregate;
        for (int j = 0;  j < n;  ++j) {
            std::cout << ' ';
            if (type.basetype == TypeDesc::FLOAT)
                std::cout << ((float *)data)[j];
            else if (type.basetype == TypeDesc::INT)
                std::cout << ((int *)data)[j];
            else if (type.basetype == TypeDesc::STRING)
                std::cout << ((ustring *)data)[j];
        }
        if (i == m_endpoint-1 || (i%8) == 7 || sym.is_uniform())
            std::cout << "\n";
        if (sym.is_uniform())
            break;
    }
}

}; // namespace pvt
}; // namespace OSL
<|endoftext|>


<commit_before>#pragma once
#include <bts/blockchain/types.hpp>
#include <map>

const static std::map<uint32_t, bts::blockchain::block_id_type> CHECKPOINT_BLOCKS
{
    {      1, bts::blockchain::block_id_type( "8abcfb93c52f999e3ef5288c4f837f4f15af5521" ) },
    { 225000, bts::blockchain::block_id_type( "2e09195c3e4ef6d58736151ea22f78f08556e6a9" ) },
    { 442700, bts::blockchain::block_id_type( "c22e2dc1954f7d3a9620048d64587018e98c03f8" ) }
};
<commit_msg>Add checkpoint<commit_after>#pragma once
#include <bts/blockchain/types.hpp>
#include <map>

const static std::map<uint32_t, bts::blockchain::block_id_type> CHECKPOINT_BLOCKS
{
    {      1, bts::blockchain::block_id_type( "8abcfb93c52f999e3ef5288c4f837f4f15af5521" ) },
    { 225000, bts::blockchain::block_id_type( "2e09195c3e4ef6d58736151ea22f78f08556e6a9" ) },
    { 442700, bts::blockchain::block_id_type( "c22e2dc1954f7d3a9620048d64587018e98c03f8" ) },
    { 452700, bts::blockchain::block_id_type( "b678b7b86a8b05593df49acc5e8ba62f7177276e" ) }
};
<|endoftext|>