<commit_before>#include "chimera/render/scene/Scene.hpp"
#include "chimera/core/MouseDevice.hpp"
#include "chimera/render/3d/RenderCommand.hpp"
#include "chimera/render/3d/RenderableSimple.hpp"
#include "chimera/render/Material.hpp"
#include "chimera/render/Transform.hpp"
#include "chimera/render/buffer/VertexArray.hpp"
#include "chimera/render/bullet/Solid.hpp"
#include "chimera/render/scene/Components.hpp"
#include "chimera/render/scene/Entity.hpp"
#include <SDL2/SDL.h>

namespace Chimera {

Scene::Scene() : camera(nullptr), viewportWidth(800), viewportHeight(640), renderBuffer(nullptr), physicsControl(nullptr) {
    // Create ShadowPass
    ShaderManager::load("./assets/shaders/ShadowMappingDepth.glsl", shadowPass.shader);
    // Define o framebuffer de Shadow
    FrameBufferSpecification fbSpec;
    fbSpec.attachments = {
        TexParam(TexFormat::DEPTH_COMPONENT, TexFormat::DEPTH_COMPONENT, TexFilter::NEAREST, TexWrap::CLAMP_TO_BORDER, TexDType::FLOAT)};

    fbSpec.width = 2048;
    fbSpec.height = 2048;
    fbSpec.swapChainTarget = false;
    fbSpec.samples = 1;

    shadowPass.shadowBuffer = new FrameBuffer(fbSpec);
    shadowPass.lightProjection = glm::ortho(-30.0f, 30.0f, -30.0f, 30.0f, 1.0f, 150.0f);
    // Note that if you use a
    // glm::mat4 lightProjection = glm::perspective(45.0f, (float)width / (float)height, near_plane, far_plane);
    // perspective projection matrix you'll have to change the light position as the
    // current light position isn't enough to reflect the whole scene.

    this->createRenderBuffer();
    emissor = nullptr;
}
Scene::~Scene() {}

void Scene::createRenderBuffer() {
    if (renderBuffer) {
        delete renderBuffer;
        renderBuffer = nullptr;
    }
    // Create RenderPass
    // Define o framebuffer de desenho
    Shader shader;
    ShaderManager::load("./assets/shaders/CanvasHMD.glsl", shader);
    FrameBufferSpecification fbSpec;
    fbSpec.attachments = {
        TexParam(TexFormat::RGBA, TexFormat::RGBA, TexFilter::LINEAR, TexWrap::CLAMP, TexDType::UNSIGNED_BYTE),
        TexParam(TexFormat::RED_INTEGER, TexFormat::R32I, TexFilter::LINEAR, TexWrap::CLAMP_TO_EDGE, TexDType::UNSIGNED_BYTE),
        TexParam(TexFormat::DEPTH_COMPONENT, TexFormat::DEPTH_ATTACHMENT, TexFilter::NONE, TexWrap::NONE, TexDType::UNSIGNED_BYTE)};

    fbSpec.width = viewportWidth;
    fbSpec.height = viewportHeight;
    fbSpec.swapChainTarget = false;
    fbSpec.samples = 1;

    renderBuffer = new RenderBuffer(0, 0, new FrameBuffer(fbSpec), shader);
}

void Scene::onDeatach() {
    // destroy scripts
    eRegistry.view<NativeScriptComponent>().each([=](auto entity, auto& nsc) {
        if (!nsc.instance) {
            nsc.instance->onDestroy();
            nsc.destroyScript(&nsc);
        }
    });
}

void Scene::onAttach() {
    // lista as tags nas entidades registradas
    eRegistry.each([&](auto entityID) {
        Entity entity{entityID, this};
        auto& tc = entity.getComponent<TagComponent>();
        SDL_Log("Tag: %s Id: %s", tc.tag.c_str(), tc.id.c_str());

        // TODO: passar para um NativeScriptComponent
        if (entity.hasComponent<PhysicsControl>()) {
            PhysicsControl& p = entity.getComponent<PhysicsControl>();
            physicsControl = &p;
        }

        // Se for um mesh inicializar componente (já que nao tenho classe de Mesh)
        if (entity.hasComponent<MeshData>()) {
            MeshData& mesh = entity.getComponent<MeshData>();

            // Inicializa Materiais
            if (entity.hasComponent<Material>()) {
                Material& material = entity.getComponent<Material>();
                if (!material.isValid())
                    material.init();
            } else {
                Material& material = entity.addComponent<Material>();
                material.setDefaultEffect();
                material.init();
            }

            // Se nja nao foi inicializado um Renderable3dComponent ao mesh
            if (!entity.hasComponent<Renderable3dComponent>()) {

                // Transforma MeshData em VertexData comprimindo-o
                std::vector<Chimera::VertexData> renderData;
                vertexDataFromMesh(&mesh, renderData);
                std::vector<uint32_t> index;
                std::vector<Chimera::VertexData> vertexDataOut;
                vertexDataIndexCompile(renderData, vertexDataOut, index);

                // Cria o renderable object com o VertexData
                Renderable3dComponent& rc = entity.addComponent<Renderable3dComponent>();
                RenderableSimple* r = new RenderableSimple();
                r->createBuffers(&vertexDataOut[0], vertexDataOut.size(), &index[0], index.size());
                r->setEntity(entity);
                rc.renderable = r;
            }

            if (entity.hasComponent<Solid>()) {
                glm::vec3 min, max, size;
                vertexDataMeshMinMaxSize(&mesh, min, max, size);

                Solid& solid = entity.getComponent<Solid>();
                solid.init(size); // Cria rigidBody iniciaza transformacao e inicializa shape se ele nao existir
            }
        }

        // TODO: melhorar!!!!
        if (entity.hasComponent<EmiterComponent>()) {
            EmiterComponent& ec = entity.getComponent<EmiterComponent>();
            emissor = ec.emitter;
        }
    });

    // initialize scripts
    eRegistry.view<NativeScriptComponent>().each([=](auto entity, auto& nsc) {
        if (!nsc.instance) {
            nsc.instance = nsc.instantiateScript();
            nsc.instance->entity = Entity{entity, this};
            nsc.instance->onCreate();
        }
    });

    // load default camera
    auto view = eRegistry.view<CameraComponent>();
    for (auto entity : view) {

        auto& cameraComponent = view.get<CameraComponent>(entity);
        if (cameraComponent.primary)
            camera = cameraComponent.camera;
    }
}

void Scene::onUpdate(const double& ts) {

    // update scripts
    eRegistry.view<NativeScriptComponent>().each([=](auto entity, auto& nsc) {
        if (nsc.instance) {
            nsc.instance->onUpdate(ts);
        }
    });

    if (camera)
        camera->recalculateMatrix(false); // FIXME: remover daqui!!!!

    if (physicsControl) {
        physicsControl->stepSim(ts);
        physicsControl->checkCollisions();
    }

    // TODO: melhorar!!!!
    if (emissor) {
        emissor->recycleLife(ts); // TODO: passar para array e melhorar onde guardar o relacionamento!!
    }
}

Entity Scene::createEntity(const std::string& name) {

    // toda entidade tem um transform
    Entity entity = {eRegistry.create(), this};
    entity.addComponent<Transform>();
    auto& tag = entity.addComponent<TagComponent>();
    tag.tag = name.empty() ? "Entity" : name;

    return entity;
}

void Scene::destroyEntity(Entity entity) { eRegistry.destroy(entity); }

void Scene::onViewportResize(uint32_t width, uint32_t height) {

    viewportWidth = width;
    viewportHeight = height;

    auto view = eRegistry.view<CameraComponent>();
    for (auto entity : view) {

        auto& cameraComponent = view.get<CameraComponent>(entity);
        if (!cameraComponent.fixedAspectRatio) {
            cameraComponent.camera->setViewportSize(width, height);
        }
    }

    createRenderBuffer();
}

void Scene::onRender() { this->render(renderBatch); }

bool Scene::onEvent(const SDL_Event& event) {
    switch (event.type) {
        case SDL_WINDOWEVENT: {
            switch (event.window.event) {
                case SDL_WINDOWEVENT_RESIZED:
                    onViewportResize(event.window.data1, event.window.data2);
                    break;
            }
        } break;
    }
    return true;
}

void Scene::execEmitterPass(ICamera* camera, IRenderer3d& renderer) {
    // TODO: melhorar!!!!
    renderer.begin(camera);

    auto view = eRegistry.view<RenderableParticle>();
    for (auto entity : view) {

        RenderableParticle& rc = view.get<RenderableParticle>(entity);
        IRenderable3d* renderable = rc.renderable;

        RenderCommand command;

        // if (renderable->getEntity().hasComponent<Solid>()) {
        //     Solid& sl = renderable->getEntity().getComponent<Solid>();
        //     command.transform = sl.getMatrix();
        // } else {
        Transform& tc = renderable->getEntity().getComponent<Transform>();
        command.transform = tc.getMatrix();
        // }

        Shader& sc = rc.renderable->getEntity().getComponent<Shader>();
        Material& mc = rc.renderable->getEntity().getComponent<Material>();

        command.renderable = renderable;
        command.shader = sc;
        mc.bindMaterialInformation(command.uniforms, command.vTex);

        command.uniforms.push_back(UniformVal("model", command.transform));

        rc.renderable->submit(camera, command, &renderer);
    }

    renderer.end();
    renderer.flush();
}

void Scene::execShadowPass(ICamera* camera, IRenderer3d& renderer) {

    renderer.begin(camera);

    // load lights after begin (clear previos lights)
    auto lightViewEnt = eRegistry.view<LightComponent>();
    for (auto entity : lightViewEnt) {
        auto& lc = lightViewEnt.get<LightComponent>(entity);
        if (lc.global) {
            // TODO: usar o direcionm depois no segundo parametro
            glm::mat4 lightView = glm::lookAt(lc.light->getPosition(), glm::vec3(0.0f), glm::vec3(0.0, 0.0, -1.0));
            shadowPass.lightSpaceMatrix = shadowPass.lightProjection * lightView;
            renderer.submitUniform(UniformVal("lightSpaceMatrix", shadowPass.lightSpaceMatrix));
        }
    }

    auto view = eRegistry.view<Renderable3dComponent>();
    for (auto entity : view) {

        Renderable3dComponent& rc = view.get<Renderable3dComponent>(entity);
        IRenderable3d* renderable = rc.renderable;

        RenderCommand command;

        if (renderable->getEntity().hasComponent<Solid>()) {
            Solid& sl = renderable->getEntity().getComponent<Solid>();
            command.transform = sl.getMatrix();
        } else {
            Transform& tc = renderable->getEntity().getComponent<Transform>();
            command.transform = tc.getMatrix();
        }

        command.renderable = renderable;
        command.shader = shadowPass.shader;
        command.uniforms.push_back(UniformVal("model", command.transform));
        rc.renderable->submit(camera, command, &renderer);
    }

    renderer.end();
    shadowPass.shadowBuffer->bind(); // we're not using the stencil buffer now
    renderer.flush();
    shadowPass.shadowBuffer->unbind();
}

void Scene::execRenderPass(ICamera* camera, IRenderer3d& renderer) {

    renderer.begin(camera);

    auto view = eRegistry.view<Renderable3dComponent>();
    for (auto entity : view) {

        Renderable3dComponent& rc = view.get<Renderable3dComponent>(entity);
        IRenderable3d* renderable = rc.renderable;

        RenderCommand command;

        if (renderable->getEntity().hasComponent<Solid>()) {
            Solid& sl = renderable->getEntity().getComponent<Solid>();
            command.transform = sl.getMatrix();
        } else {
            Transform& tc = renderable->getEntity().getComponent<Transform>();
            command.transform = tc.getMatrix();
        }

        Shader& sc = rc.renderable->getEntity().getComponent<Shader>();
        Material& mc = rc.renderable->getEntity().getComponent<Material>();

        command.renderable = renderable;
        command.shader = sc;
        mc.bindMaterialInformation(command.uniforms, command.vTex);

        command.uniforms.push_back(UniformVal("model", command.transform));

        rc.renderable->submit(camera, command, &renderer);
    }

    renderer.end();
    renderBuffer->bind(); // we're not using the stencil buffer now
    renderer.flush();

    // get val from color buffer (must be inside framebuffer renderer
    glm::ivec2 pos = MouseDevice::getMove();
    pos.y = viewportHeight - pos.y;
    int val = renderBuffer->getFramBuffer()->readPixel(1, pos.x, pos.y);
    SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "mouse(X: %d / Y: %d): %d", pos.x, pos.y, val);

    // renderBuffer->unbind();
}

void Scene::render(IRenderer3d& renderer) {

    if (renderer.getLog() == true) {
        glm::vec3 pos = camera->getPosition();
        SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Eye: %0.2f; %0.3f; %0.3f", pos.x, pos.y, pos.z);
    }

    // render a shadows in framebuffer
    this->execShadowPass(camera, renderer);

    // used by all
    renderer.submitUniform(UniformVal("projection", camera->getProjectionMatrix()));
    renderer.submitUniform(UniformVal("view", camera->getViewMatrix()));

    // data from shadowPass
    renderer.submitUniform(UniformVal("lightSpaceMatrix", shadowPass.lightSpaceMatrix));
    renderer.submitUniform(UniformVal("viewPos", camera->getPosition()));
    renderer.submitUniform(UniformVal("shadows", 1));   // Ativa a sombra com 1
    renderer.submitUniform(UniformVal("shadowMap", 1)); // id da textura de shadow

    shadowPass.shadowBuffer->getDepthAttachemnt()->bind(1);

    auto lightView = eRegistry.view<LightComponent>();
    for (auto entity : lightView) {
        auto& lc = lightView.get<LightComponent>(entity);
        if (lc.global) {
            renderer.submitLight(lc.light);
        }
    }

    this->execRenderPass(camera, renderer);

    // AQUI
    if (emissor)
        this->execEmitterPass(camera, renderParticleEmitter);

    renderBuffer->unbind();
    renderBuffer->render();
}
} // namespace Chimera<commit_msg>ajustes<commit_after>#include "chimera/render/scene/Scene.hpp"
#include "chimera/core/MouseDevice.hpp"
#include "chimera/render/3d/RenderCommand.hpp"
#include "chimera/render/3d/RenderableSimple.hpp"
#include "chimera/render/Material.hpp"
#include "chimera/render/Transform.hpp"
#include "chimera/render/buffer/VertexArray.hpp"
#include "chimera/render/bullet/Solid.hpp"
#include "chimera/render/scene/Components.hpp"
#include "chimera/render/scene/Entity.hpp"
#include <SDL2/SDL.h>

namespace Chimera {

Scene::Scene() : camera(nullptr), viewportWidth(800), viewportHeight(640), renderBuffer(nullptr), physicsControl(nullptr) {
    // Create ShadowPass
    ShaderManager::load("./assets/shaders/ShadowMappingDepth.glsl", shadowPass.shader);
    // Define o framebuffer de Shadow
    FrameBufferSpecification fbSpec;
    fbSpec.attachments = {
        TexParam(TexFormat::DEPTH_COMPONENT, TexFormat::DEPTH_COMPONENT, TexFilter::NEAREST, TexWrap::CLAMP_TO_BORDER, TexDType::FLOAT)};

    fbSpec.width = 2048;
    fbSpec.height = 2048;
    fbSpec.swapChainTarget = false;
    fbSpec.samples = 1;

    shadowPass.shadowBuffer = new FrameBuffer(fbSpec);
    shadowPass.lightProjection = glm::ortho(-30.0f, 30.0f, -30.0f, 30.0f, 1.0f, 150.0f);
    // Note that if you use a
    // glm::mat4 lightProjection = glm::perspective(45.0f, (float)width / (float)height, near_plane, far_plane);
    // perspective projection matrix you'll have to change the light position as the
    // current light position isn't enough to reflect the whole scene.

    this->createRenderBuffer();
    emissor = nullptr;
}
Scene::~Scene() {}

void Scene::createRenderBuffer() {
    if (renderBuffer) {
        delete renderBuffer;
        renderBuffer = nullptr;
    }
    // Create RenderPass
    // Define o framebuffer de desenho
    Shader shader;
    ShaderManager::load("./assets/shaders/CanvasHMD.glsl", shader);
    FrameBufferSpecification fbSpec;
    fbSpec.attachments = {
        TexParam(TexFormat::RGBA, TexFormat::RGBA, TexFilter::LINEAR, TexWrap::CLAMP, TexDType::UNSIGNED_BYTE),
        TexParam(TexFormat::RED_INTEGER, TexFormat::R32I, TexFilter::LINEAR, TexWrap::CLAMP_TO_EDGE, TexDType::UNSIGNED_BYTE),
        TexParam(TexFormat::DEPTH_COMPONENT, TexFormat::DEPTH_ATTACHMENT, TexFilter::NONE, TexWrap::NONE, TexDType::UNSIGNED_BYTE)};

    fbSpec.width = viewportWidth;
    fbSpec.height = viewportHeight;
    fbSpec.swapChainTarget = false;
    fbSpec.samples = 1;

    renderBuffer = new RenderBuffer(0, 0, new FrameBuffer(fbSpec), shader);
}

void Scene::onDeatach() {
    // destroy scripts
    eRegistry.view<NativeScriptComponent>().each([=](auto entity, auto& nsc) {
        if (!nsc.instance) {
            nsc.instance->onDestroy();
            nsc.destroyScript(&nsc);
        }
    });
}

void Scene::onAttach() {
    // lista as tags nas entidades registradas
    eRegistry.each([&](auto entityID) {
        Entity entity{entityID, this};
        auto& tc = entity.getComponent<TagComponent>();
        SDL_Log("Tag: %s Id: %s", tc.tag.c_str(), tc.id.c_str());

        // TODO: passar para um NativeScriptComponent
        if (entity.hasComponent<PhysicsControl>()) {
            PhysicsControl& p = entity.getComponent<PhysicsControl>();
            physicsControl = &p;
        }

        // Se for um mesh inicializar componente (já que nao tenho classe de Mesh)
        if (entity.hasComponent<MeshData>()) {
            MeshData& mesh = entity.getComponent<MeshData>();

            // Inicializa Materiais
            if (entity.hasComponent<Material>()) {
                Material& material = entity.getComponent<Material>();
                if (!material.isValid())
                    material.init();
            } else {
                Material& material = entity.addComponent<Material>();
                material.setDefaultEffect();
                material.init();
            }

            // Se nja nao foi inicializado um Renderable3dComponent ao mesh
            if (!entity.hasComponent<Renderable3dComponent>()) {

                // Transforma MeshData em VertexData comprimindo-o
                std::vector<Chimera::VertexData> renderData;
                vertexDataFromMesh(&mesh, renderData);
                std::vector<uint32_t> index;
                std::vector<Chimera::VertexData> vertexDataOut;
                vertexDataIndexCompile(renderData, vertexDataOut, index);

                // Cria o renderable object com o VertexData
                Renderable3dComponent& rc = entity.addComponent<Renderable3dComponent>();
                RenderableSimple* r = new RenderableSimple();
                r->createBuffers(&vertexDataOut[0], vertexDataOut.size(), &index[0], index.size());
                r->setEntity(entity);
                rc.renderable = r;
            }

            if (entity.hasComponent<Solid>()) {
                glm::vec3 min, max, size;
                vertexDataMeshMinMaxSize(&mesh, min, max, size);

                Solid& solid = entity.getComponent<Solid>();
                solid.init(size); // Cria rigidBody iniciaza transformacao e inicializa shape se ele nao existir
            }
        }

        // TODO: melhorar!!!!
        if (entity.hasComponent<EmiterComponent>()) {
            EmiterComponent& ec = entity.getComponent<EmiterComponent>();
            emissor = ec.emitter;
        }
    });

    // initialize scripts
    eRegistry.view<NativeScriptComponent>().each([=](auto entity, auto& nsc) {
        if (!nsc.instance) {
            nsc.instance = nsc.instantiateScript();
            nsc.instance->entity = Entity{entity, this};
            nsc.instance->onCreate();
        }
    });

    // load default camera
    auto view = eRegistry.view<CameraComponent>();
    for (auto entity : view) {

        auto& cameraComponent = view.get<CameraComponent>(entity);
        if (cameraComponent.primary)
            camera = cameraComponent.camera;
    }
}

void Scene::onUpdate(const double& ts) {

    // update scripts
    eRegistry.view<NativeScriptComponent>().each([=](auto entity, auto& nsc) {
        if (nsc.instance) {
            nsc.instance->onUpdate(ts);
        }
    });

    if (camera)
        camera->recalculateMatrix(false); // FIXME: remover daqui!!!!

    if (physicsControl) {
        physicsControl->stepSim(ts);
        physicsControl->checkCollisions();
    }

    // TODO: melhorar!!!!
    if (emissor) {
        emissor->recycleLife(ts); // TODO: passar para array e melhorar onde guardar o relacionamento!!
    }
}

Entity Scene::createEntity(const std::string& name) {

    // toda entidade tem um transform
    Entity entity = {eRegistry.create(), this};
    entity.addComponent<Transform>();
    auto& tag = entity.addComponent<TagComponent>();
    tag.tag = name.empty() ? "Entity" : name;

    return entity;
}

void Scene::destroyEntity(Entity entity) { eRegistry.destroy(entity); }

void Scene::onViewportResize(uint32_t width, uint32_t height) {

    viewportWidth = width;
    viewportHeight = height;

    auto view = eRegistry.view<CameraComponent>();
    for (auto entity : view) {

        auto& cameraComponent = view.get<CameraComponent>(entity);
        if (!cameraComponent.fixedAspectRatio) {
            cameraComponent.camera->setViewportSize(width, height);
        }
    }

    createRenderBuffer();
}

void Scene::onRender() { this->render(renderBatch); }

bool Scene::onEvent(const SDL_Event& event) {
    switch (event.type) {
        case SDL_WINDOWEVENT: {
            switch (event.window.event) {
                case SDL_WINDOWEVENT_RESIZED:
                    onViewportResize(event.window.data1, event.window.data2);
                    break;
            }
        } break;
    }
    return true;
}

void Scene::execEmitterPass(ICamera* camera, IRenderer3d& renderer) {

    auto view = eRegistry.view<RenderableParticle>();
    for (auto entity : view) {

        RenderableParticle& rc = view.get<RenderableParticle>(entity);
        IRenderable3d* renderable = rc.renderable;

        RenderCommand command;

        if (renderable->getEntity().hasComponent<Solid>()) {
            Solid& sl = renderable->getEntity().getComponent<Solid>();
            command.transform = sl.getMatrix();
        } else {
            Transform& tc = renderable->getEntity().getComponent<Transform>();
            command.transform = tc.getMatrix();
        }

        Shader& sc = rc.renderable->getEntity().getComponent<Shader>();
        Material& mc = rc.renderable->getEntity().getComponent<Material>();

        command.renderable = renderable;
        command.shader = sc;
        mc.bindMaterialInformation(command.uniforms, command.vTex);

        command.uniforms.push_back(UniformVal("model", command.transform));

        rc.renderable->submit(camera, command, &renderer);
    }
}

void Scene::execShadowPass(ICamera* camera, IRenderer3d& renderer) {

    // load lights after begin (clear previos lights)
    auto lightViewEnt = eRegistry.view<LightComponent>();
    for (auto entity : lightViewEnt) {
        auto& lc = lightViewEnt.get<LightComponent>(entity);
        if (lc.global) {
            // TODO: usar o direcionm depois no segundo parametro
            glm::mat4 lightView = glm::lookAt(lc.light->getPosition(), glm::vec3(0.0f), glm::vec3(0.0, 0.0, -1.0));
            shadowPass.lightSpaceMatrix = shadowPass.lightProjection * lightView;
            renderer.submitUniform(UniformVal("lightSpaceMatrix", shadowPass.lightSpaceMatrix));
        }
    }

    auto view = eRegistry.view<Renderable3dComponent>();
    for (auto entity : view) {

        Renderable3dComponent& rc = view.get<Renderable3dComponent>(entity);
        IRenderable3d* renderable = rc.renderable;

        RenderCommand command;

        if (renderable->getEntity().hasComponent<Solid>()) {
            Solid& sl = renderable->getEntity().getComponent<Solid>();
            command.transform = sl.getMatrix();
        } else {
            Transform& tc = renderable->getEntity().getComponent<Transform>();
            command.transform = tc.getMatrix();
        }

        command.renderable = renderable;
        command.shader = shadowPass.shader;
        command.uniforms.push_back(UniformVal("model", command.transform));
        rc.renderable->submit(camera, command, &renderer);
    }
}

void Scene::execRenderPass(ICamera* camera, IRenderer3d& renderer) {
    auto view = eRegistry.view<Renderable3dComponent>();
    for (auto entity : view) {

        Renderable3dComponent& rc = view.get<Renderable3dComponent>(entity);
        IRenderable3d* renderable = rc.renderable;

        RenderCommand command;

        if (renderable->getEntity().hasComponent<Solid>()) {
            Solid& sl = renderable->getEntity().getComponent<Solid>();
            command.transform = sl.getMatrix();
        } else {
            Transform& tc = renderable->getEntity().getComponent<Transform>();
            command.transform = tc.getMatrix();
        }

        Shader& sc = rc.renderable->getEntity().getComponent<Shader>();
        Material& mc = rc.renderable->getEntity().getComponent<Material>();

        command.renderable = renderable;
        command.shader = sc;
        mc.bindMaterialInformation(command.uniforms, command.vTex);

        command.uniforms.push_back(UniformVal("model", command.transform));

        rc.renderable->submit(camera, command, &renderer);
    }
}

void Scene::render(IRenderer3d& renderer) {

    if (renderer.getLog() == true) {
        glm::vec3 pos = camera->getPosition();
        SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Eye: %0.2f; %0.3f; %0.3f", pos.x, pos.y, pos.z);
    }

    { // render a shadows in framebuffer
        renderer.begin(camera);
        this->execShadowPass(camera, renderer);

        renderer.end();
        shadowPass.shadowBuffer->bind(); // we're not using the stencil buffer now

        renderer.flush();
        shadowPass.shadowBuffer->unbind();
    }

    // used by all
    renderer.submitUniform(UniformVal("projection", camera->getProjectionMatrix()));
    renderer.submitUniform(UniformVal("view", camera->getViewMatrix()));

    // data from shadowPass
    renderer.submitUniform(UniformVal("lightSpaceMatrix", shadowPass.lightSpaceMatrix));
    renderer.submitUniform(UniformVal("viewPos", camera->getPosition()));
    renderer.submitUniform(UniformVal("shadows", 1));   // Ativa a sombra com 1
    renderer.submitUniform(UniformVal("shadowMap", 1)); // id da textura de shadow

    shadowPass.shadowBuffer->getDepthAttachemnt()->bind(1);

    auto lightView = eRegistry.view<LightComponent>();
    for (auto entity : lightView) {
        auto& lc = lightView.get<LightComponent>(entity);
        if (lc.global) {
            renderer.submitLight(lc.light);
        }
    }

    { // Render mesh
        renderer.begin(camera);
        this->execRenderPass(camera, renderer);

        renderer.end();
        renderBuffer->bind(); // we're not using the stencil buffer now

        renderer.flush();
    }

    if (emissor) { // Render emissores
        renderParticleEmitter.begin(camera);
        this->execEmitterPass(camera, renderParticleEmitter);

        renderParticleEmitter.end();
        renderParticleEmitter.flush();
    }

    {
        // get val from color buffer (must be inside framebuffer renderer
        glm::ivec2 pos = MouseDevice::getMove();
        pos.y = viewportHeight - pos.y;
        int val = renderBuffer->getFramBuffer()->readPixel(1, pos.x, pos.y);
        SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "mouse(X: %d / Y: %d): %d", pos.x, pos.y, val);
    }

    renderBuffer->unbind();
    renderBuffer->render();
}
} // namespace Chimera<|endoftext|>


<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 "base/string_util.h"
#include "base/test/test_timeouts.h"
#include "base/threading/platform_thread.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "chrome/browser/net/url_request_failed_dns_job.h"
#include "chrome/browser/net/url_request_mock_http_job.h"
#include "net/test/test_server.h"

class ErrorPageTest : public UITest {
 protected:
  bool WaitForTitleMatching(const std::wstring& title) {
    for (int i = 0; i < 10; ++i) {
      if (GetActiveTabTitle() == title)
        return true;
      base::PlatformThread::Sleep(TestTimeouts::action_timeout_ms());
    }
    EXPECT_EQ(title, GetActiveTabTitle());
    return false;
  }
};

TEST_F(ErrorPageTest, DNSError_Basic) {
  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);

  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
}

TEST_F(ErrorPageTest, DNSError_GoBack1) {
  // Test that a DNS error occuring in the main frame does not result in an
  // additional session history entry.
  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title2.html"))));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));

  EXPECT_TRUE(GetActiveTab()->GoBack());

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}

TEST_F(ErrorPageTest, DNSError_GoBack2) {
  // Test that a DNS error occuring in the main frame does not result in an
  // additional session history entry.
  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title2.html"))));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title3.html"))));

  // The first navigation should fail, and the second one should be the error
  // page.
  EXPECT_TRUE(GetActiveTab()->GoBackBlockUntilNavigationsComplete(2));
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  EXPECT_TRUE(GetActiveTab()->GoBack());

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}

TEST_F(ErrorPageTest, DNSError_GoBack2AndForward) {
  // Test that a DNS error occuring in the main frame does not result in an
  // additional session history entry.

  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title2.html"))));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title3.html"))));

  // The first navigation should fail, and the second one should be the error
  // page.
  EXPECT_TRUE(GetActiveTab()->GoBackBlockUntilNavigationsComplete(2));
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  EXPECT_TRUE(GetActiveTab()->GoBack());
  // The first navigation should fail, and the second one should be the error
  // page.
  EXPECT_TRUE(GetActiveTab()->GoForwardBlockUntilNavigationsComplete(2));

  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
}

// Flaky on Linux x64, see http://crbug.com/79412
#if defined(OS_LINUX) && defined(ARCH_CPU_64_BITS)
#define MAYBE_DNSError_GoBack2Forward2 FLAKY_DNSError_GoBack2Forward2
#else
#define MAYBE_DNSError_GoBack2Forward2 DNSError_GoBack2Forward2
#endif
TEST_F(ErrorPageTest, DNSError_GoBack2Forward2) {
  // Test that a DNS error occuring in the main frame does not result in an
  // additional session history entry.

  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title3.html"))));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title2.html"))));

  // The first navigation should fail, and the second one should be the error
  // page.
  EXPECT_TRUE(GetActiveTab()->GoBackBlockUntilNavigationsComplete(2));
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  EXPECT_TRUE(GetActiveTab()->GoBack());
  // The first navigation should fail, and the second one should be the error
  // page.
  EXPECT_TRUE(GetActiveTab()->GoForwardBlockUntilNavigationsComplete(2));
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  EXPECT_TRUE(GetActiveTab()->GoForward());

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}

TEST_F(ErrorPageTest, IFrameDNSError_Basic) {
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("iframe_dns_error.html"))));
  EXPECT_TRUE(WaitForTitleMatching(L"Blah"));
}

TEST_F(ErrorPageTest, IFrameDNSError_GoBack) {
  // Test that a DNS error occuring in an iframe does not result in an
  // additional session history entry.

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title2.html"))));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("iframe_dns_error.html"))));

  EXPECT_TRUE(GetActiveTab()->GoBack());

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}

TEST_F(ErrorPageTest, IFrameDNSError_GoBackAndForward) {
  // Test that a DNS error occuring in an iframe does not result in an
  // additional session history entry.

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title2.html"))));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("iframe_dns_error.html"))));

  EXPECT_TRUE(GetActiveTab()->GoBack());
  EXPECT_TRUE(GetActiveTab()->GoForward());

  EXPECT_TRUE(WaitForTitleMatching(L"Blah"));
}

// Checks that the Link Doctor is not loaded when we receive an actual 404 page.
TEST_F(ErrorPageTest, Page404) {
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("page404.html"))));

  EXPECT_TRUE(WaitForTitleMatching(L"SUCCESS"));
}
<commit_msg>Disable flaky error page tests<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 "base/string_util.h"
#include "base/test/test_timeouts.h"
#include "base/threading/platform_thread.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "chrome/browser/net/url_request_failed_dns_job.h"
#include "chrome/browser/net/url_request_mock_http_job.h"
#include "net/test/test_server.h"

class ErrorPageTest : public UITest {
 protected:
  bool WaitForTitleMatching(const std::wstring& title) {
    for (int i = 0; i < 10; ++i) {
      if (GetActiveTabTitle() == title)
        return true;
      base::PlatformThread::Sleep(TestTimeouts::action_timeout_ms());
    }
    EXPECT_EQ(title, GetActiveTabTitle());
    return false;
  }
};

TEST_F(ErrorPageTest, DNSError_Basic) {
  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);

  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
}

TEST_F(ErrorPageTest, DNSError_GoBack1) {
  // Test that a DNS error occuring in the main frame does not result in an
  // additional session history entry.
  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title2.html"))));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));

  EXPECT_TRUE(GetActiveTab()->GoBack());

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}

// Flaky on Linux, see http://crbug.com/19361
#if defined(OS_LINUX)
#define MAYBE_DNSError_GoBack2 FLAKY_DNSError_GoBack2
#else
#define MAYBE_DNSError_GoBack2 DNSError_GoBack2
#endif
TEST_F(ErrorPageTest, MAYBE_DNSError_GoBack2) {
  // Test that a DNS error occuring in the main frame does not result in an
  // additional session history entry.
  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title2.html"))));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title3.html"))));

  // The first navigation should fail, and the second one should be the error
  // page.
  EXPECT_TRUE(GetActiveTab()->GoBackBlockUntilNavigationsComplete(2));
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  EXPECT_TRUE(GetActiveTab()->GoBack());

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}

// Flaky on Linux, see http://crbug.com/19361
#if defined(OS_LINUX)
#define MAYBE_DNSError_GoBack2AndForwar FLAKY_DNSError_GoBack2AndForwar
#else
#define MAYBE_DNSError_GoBack2AndForwar DNSError_GoBack2AndForwar
#endif
TEST_F(ErrorPageTest, MAYBE_DNSError_GoBack2AndForward) {
  // Test that a DNS error occuring in the main frame does not result in an
  // additional session history entry.

  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title2.html"))));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title3.html"))));

  // The first navigation should fail, and the second one should be the error
  // page.
  EXPECT_TRUE(GetActiveTab()->GoBackBlockUntilNavigationsComplete(2));
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  EXPECT_TRUE(GetActiveTab()->GoBack());
  // The first navigation should fail, and the second one should be the error
  // page.
  EXPECT_TRUE(GetActiveTab()->GoForwardBlockUntilNavigationsComplete(2));

  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
}

// Flaky on Linux, see http://crbug.com/19361
#if defined(OS_LINUX)
#define MAYBE_DNSError_GoBack2Forward2 FLAKY_DNSError_GoBack2Forward2
#else
#define MAYBE_DNSError_GoBack2Forward2 DNSError_GoBack2Forward2
#endif
TEST_F(ErrorPageTest, MAYBE_DNSError_GoBack2Forward2) {
  // Test that a DNS error occuring in the main frame does not result in an
  // additional session history entry.

  GURL test_url(URLRequestFailedDnsJob::kTestUrl);

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title3.html"))));
  // The first navigation should fail, and the second one should be the error
  // page.
  NavigateToURLBlockUntilNavigationsComplete(test_url, 2);
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title2.html"))));

  // The first navigation should fail, and the second one should be the error
  // page.
  EXPECT_TRUE(GetActiveTab()->GoBackBlockUntilNavigationsComplete(2));
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  EXPECT_TRUE(GetActiveTab()->GoBack());
  // The first navigation should fail, and the second one should be the error
  // page.
  EXPECT_TRUE(GetActiveTab()->GoForwardBlockUntilNavigationsComplete(2));
  EXPECT_TRUE(WaitForTitleMatching(L"Mock Link Doctor"));
  EXPECT_TRUE(GetActiveTab()->GoForward());

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}

TEST_F(ErrorPageTest, IFrameDNSError_Basic) {
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("iframe_dns_error.html"))));
  EXPECT_TRUE(WaitForTitleMatching(L"Blah"));
}

TEST_F(ErrorPageTest, IFrameDNSError_GoBack) {
  // Test that a DNS error occuring in an iframe does not result in an
  // additional session history entry.

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title2.html"))));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("iframe_dns_error.html"))));

  EXPECT_TRUE(GetActiveTab()->GoBack());

  EXPECT_TRUE(WaitForTitleMatching(L"Title Of Awesomeness"));
}

TEST_F(ErrorPageTest, IFrameDNSError_GoBackAndForward) {
  // Test that a DNS error occuring in an iframe does not result in an
  // additional session history entry.

  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("title2.html"))));
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("iframe_dns_error.html"))));

  EXPECT_TRUE(GetActiveTab()->GoBack());
  EXPECT_TRUE(GetActiveTab()->GoForward());

  EXPECT_TRUE(WaitForTitleMatching(L"Blah"));
}

// Checks that the Link Doctor is not loaded when we receive an actual 404 page.
TEST_F(ErrorPageTest, Page404) {
  NavigateToURL(URLRequestMockHTTPJob::GetMockUrl(
                    FilePath(FILE_PATH_LITERAL("page404.html"))));

  EXPECT_TRUE(WaitForTitleMatching(L"SUCCESS"));
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 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.

// Tests for the top plugins to catch regressions in our plugin host code, as
// well as in the out of process code.  Currently this tests:
//  Flash
//  Real
//  QuickTime
//  Windows Media Player
//    -this includes both WMP plugins.  npdsplay.dll is the older one that
//     comes with XP.  np-mswmp.dll can be downloaded from Microsoft and
//     needs SP2 or Vista.

#include "build/build_config.h"

#if defined(OS_WIN)
#include <windows.h>
#include <shellapi.h>
#include <shlobj.h>
#include <comutil.h>
#endif

#include <stdlib.h>
#include <string.h>
#include <memory.h>

#include <string>

#include "base/file_path.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "chrome/browser/net/url_request_mock_http_job.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"
#include "third_party/npapi/bindings/npapi.h"
#include "webkit/glue/plugins/plugin_constants_win.h"
#include "webkit/glue/plugins/plugin_list.h"

#if defined(OS_WIN)
#include "base/registry.h"
#endif

class PluginTest : public UITest {
 protected:
#if defined(OS_WIN)
  virtual void SetUp() {
    const testing::TestInfo* const test_info =
        testing::UnitTest::GetInstance()->current_test_info();
    if (strcmp(test_info->name(), "MediaPlayerNew") == 0) {
      // The installer adds our process names to the registry key below.  Since
      // the installer might not have run on this machine, add it manually.
      RegKey regkey;
      if (regkey.Open(HKEY_LOCAL_MACHINE,
                      L"Software\\Microsoft\\MediaPlayer\\ShimInclusionList",
                      KEY_WRITE)) {
        regkey.CreateKey(L"CHROME.EXE", KEY_READ);
      }
    } else if (strcmp(test_info->name(), "MediaPlayerOld") == 0) {
      // When testing the old WMP plugin, we need to force Chrome to not load
      // the new plugin.
      launch_arguments_.AppendSwitch(kUseOldWMPPluginSwitch);
    } else if (strcmp(test_info->name(), "FlashSecurity") == 0) {
      launch_arguments_.AppendSwitchASCII(switches::kTestSandbox,
                                          "security_tests.dll");
    }

    UITest::SetUp();
  }
#endif  // defined(OS_WIN)

  void TestPlugin(const std::string& test_case,
                  int timeout,
                  bool mock_http) {
    GURL url = GetTestUrl(test_case, mock_http);
    NavigateToURL(url);
    WaitForFinish(timeout, mock_http);
  }

  // Generate the URL for testing a particular test.
  // HTML for the tests is all located in test_directory\plugin\<testcase>
  // Set |mock_http| to true to use mock HTTP server.
  GURL GetTestUrl(const std::string &test_case, bool mock_http) {
    static const FilePath::CharType kPluginPath[] = FILE_PATH_LITERAL("plugin");
    if (mock_http) {
      FilePath plugin_path = FilePath(kPluginPath).AppendASCII(test_case);
      return URLRequestMockHTTPJob::GetMockUrl(plugin_path);
    }

    FilePath path;
    PathService::Get(chrome::DIR_TEST_DATA, &path);
    path = path.Append(kPluginPath).AppendASCII(test_case);
    return net::FilePathToFileURL(path);
  }

  // Waits for the test case to finish.
  void WaitForFinish(const int wait_time, bool mock_http) {
    static const char kTestCompleteCookie[] = "status";
    static const char kTestCompleteSuccess[] = "OK";

    GURL url = GetTestUrl("done", mock_http);
    scoped_refptr<TabProxy> tab(GetActiveTab());

    const std::string result =
        WaitUntilCookieNonEmpty(tab, url, kTestCompleteCookie, wait_time);
    ASSERT_EQ(kTestCompleteSuccess, result);
  }
};

TEST_F(PluginTest, Flash) {
  // Note: This does not work with the npwrapper on 64-bit Linux. Install the
  // native 64-bit Flash to run the test.
  // TODO(thestig) Update this list if we decide to only test against internal
  // Flash plugin in the future?
  std::string kFlashQuery =
#if defined(OS_WIN)
      "npswf32.dll"
#elif defined(OS_MACOSX)
      "Flash Player.plugin"
#elif defined(OS_POSIX)
      "libflashplayer.so"
#endif
      ;
  TestPlugin("flash.html?" + kFlashQuery, action_max_timeout_ms(), false);
}

#if defined(OS_WIN)
// Windows only test
TEST_F(PluginTest, FlashSecurity) {
  TestPlugin("flash.html", action_max_timeout_ms(), false);
}
#endif  // defined(OS_WIN)

#if defined(OS_WIN)
// TODO(port) Port the following tests to platforms that have the required
// plugins.
TEST_F(PluginTest, Quicktime) {
  TestPlugin("quicktime.html", action_max_timeout_ms(), false);
}

// Disabled on Release bots - http://crbug.com/44662
#if defined(NDEBUG)
#define MediaPlayerNew DISABLED_MediaPlayerNew
#endif
TEST_F(PluginTest, MediaPlayerNew) {
  TestPlugin("wmp_new.html", action_max_timeout_ms(), false);
}

// http://crbug.com/4809
TEST_F(PluginTest, DISABLED_MediaPlayerOld) {
  TestPlugin("wmp_old.html", action_max_timeout_ms(), false);
}

#if defined(NDEBUG)
#define Real DISABLED_Real
#endif
// Disabled on Release bots - http://crbug.com/44673
TEST_F(PluginTest, Real) {
  TestPlugin("real.html", action_max_timeout_ms(), false);
}

TEST_F(PluginTest, FlashOctetStream) {
  TestPlugin("flash-octet-stream.html", action_max_timeout_ms(), false);
}

// http://crbug.com/16114
TEST_F(PluginTest, FlashLayoutWhilePainting) {
  TestPlugin("flash-layout-while-painting.html", action_max_timeout_ms(), true);
}

// http://crbug.com/8690
TEST_F(PluginTest, DISABLED_Java) {
  TestPlugin("Java.html", action_max_timeout_ms(), false);
}

TEST_F(PluginTest, Silverlight) {
  TestPlugin("silverlight.html", action_max_timeout_ms(), false);
}
#endif  // defined(OS_WIN)
<commit_msg>Mark PluginTest.FlashLayoutWhilePainting as flaky on Windows.<commit_after>// Copyright (c) 2010 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.

// Tests for the top plugins to catch regressions in our plugin host code, as
// well as in the out of process code.  Currently this tests:
//  Flash
//  Real
//  QuickTime
//  Windows Media Player
//    -this includes both WMP plugins.  npdsplay.dll is the older one that
//     comes with XP.  np-mswmp.dll can be downloaded from Microsoft and
//     needs SP2 or Vista.

#include "build/build_config.h"

#if defined(OS_WIN)
#include <windows.h>
#include <shellapi.h>
#include <shlobj.h>
#include <comutil.h>
#endif

#include <stdlib.h>
#include <string.h>
#include <memory.h>

#include <string>

#include "base/file_path.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "chrome/browser/net/url_request_mock_http_job.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"
#include "third_party/npapi/bindings/npapi.h"
#include "webkit/glue/plugins/plugin_constants_win.h"
#include "webkit/glue/plugins/plugin_list.h"

#if defined(OS_WIN)
#include "base/registry.h"
#endif

class PluginTest : public UITest {
 protected:
#if defined(OS_WIN)
  virtual void SetUp() {
    const testing::TestInfo* const test_info =
        testing::UnitTest::GetInstance()->current_test_info();
    if (strcmp(test_info->name(), "MediaPlayerNew") == 0) {
      // The installer adds our process names to the registry key below.  Since
      // the installer might not have run on this machine, add it manually.
      RegKey regkey;
      if (regkey.Open(HKEY_LOCAL_MACHINE,
                      L"Software\\Microsoft\\MediaPlayer\\ShimInclusionList",
                      KEY_WRITE)) {
        regkey.CreateKey(L"CHROME.EXE", KEY_READ);
      }
    } else if (strcmp(test_info->name(), "MediaPlayerOld") == 0) {
      // When testing the old WMP plugin, we need to force Chrome to not load
      // the new plugin.
      launch_arguments_.AppendSwitch(kUseOldWMPPluginSwitch);
    } else if (strcmp(test_info->name(), "FlashSecurity") == 0) {
      launch_arguments_.AppendSwitchASCII(switches::kTestSandbox,
                                          "security_tests.dll");
    }

    UITest::SetUp();
  }
#endif  // defined(OS_WIN)

  void TestPlugin(const std::string& test_case,
                  int timeout,
                  bool mock_http) {
    GURL url = GetTestUrl(test_case, mock_http);
    NavigateToURL(url);
    WaitForFinish(timeout, mock_http);
  }

  // Generate the URL for testing a particular test.
  // HTML for the tests is all located in test_directory\plugin\<testcase>
  // Set |mock_http| to true to use mock HTTP server.
  GURL GetTestUrl(const std::string &test_case, bool mock_http) {
    static const FilePath::CharType kPluginPath[] = FILE_PATH_LITERAL("plugin");
    if (mock_http) {
      FilePath plugin_path = FilePath(kPluginPath).AppendASCII(test_case);
      return URLRequestMockHTTPJob::GetMockUrl(plugin_path);
    }

    FilePath path;
    PathService::Get(chrome::DIR_TEST_DATA, &path);
    path = path.Append(kPluginPath).AppendASCII(test_case);
    return net::FilePathToFileURL(path);
  }

  // Waits for the test case to finish.
  void WaitForFinish(const int wait_time, bool mock_http) {
    static const char kTestCompleteCookie[] = "status";
    static const char kTestCompleteSuccess[] = "OK";

    GURL url = GetTestUrl("done", mock_http);
    scoped_refptr<TabProxy> tab(GetActiveTab());

    const std::string result =
        WaitUntilCookieNonEmpty(tab, url, kTestCompleteCookie, wait_time);
    ASSERT_EQ(kTestCompleteSuccess, result);
  }
};

TEST_F(PluginTest, Flash) {
  // Note: This does not work with the npwrapper on 64-bit Linux. Install the
  // native 64-bit Flash to run the test.
  // TODO(thestig) Update this list if we decide to only test against internal
  // Flash plugin in the future?
  std::string kFlashQuery =
#if defined(OS_WIN)
      "npswf32.dll"
#elif defined(OS_MACOSX)
      "Flash Player.plugin"
#elif defined(OS_POSIX)
      "libflashplayer.so"
#endif
      ;
  TestPlugin("flash.html?" + kFlashQuery, action_max_timeout_ms(), false);
}

#if defined(OS_WIN)
// Windows only test
TEST_F(PluginTest, FlashSecurity) {
  TestPlugin("flash.html", action_max_timeout_ms(), false);
}
#endif  // defined(OS_WIN)

#if defined(OS_WIN)
// TODO(port) Port the following tests to platforms that have the required
// plugins.
TEST_F(PluginTest, Quicktime) {
  TestPlugin("quicktime.html", action_max_timeout_ms(), false);
}

// Disabled on Release bots - http://crbug.com/44662
#if defined(NDEBUG)
#define MediaPlayerNew DISABLED_MediaPlayerNew
#endif
TEST_F(PluginTest, MediaPlayerNew) {
  TestPlugin("wmp_new.html", action_max_timeout_ms(), false);
}

// http://crbug.com/4809
TEST_F(PluginTest, DISABLED_MediaPlayerOld) {
  TestPlugin("wmp_old.html", action_max_timeout_ms(), false);
}

#if defined(NDEBUG)
#define Real DISABLED_Real
#endif
// Disabled on Release bots - http://crbug.com/44673
TEST_F(PluginTest, Real) {
  TestPlugin("real.html", action_max_timeout_ms(), false);
}

TEST_F(PluginTest, FlashOctetStream) {
  TestPlugin("flash-octet-stream.html", action_max_timeout_ms(), false);
}

#if defined(OS_WIN)
// http://crbug.com/53926
TEST_F(PluginTest, FLAKY_FlashLayoutWhilePainting) {
#else
TEST_F(PluginTest, FlashLayoutWhilePainting) {
#endif
  TestPlugin("flash-layout-while-painting.html", action_max_timeout_ms(), true);
}

// http://crbug.com/8690
TEST_F(PluginTest, DISABLED_Java) {
  TestPlugin("Java.html", action_max_timeout_ms(), false);
}

TEST_F(PluginTest, Silverlight) {
  TestPlugin("silverlight.html", action_max_timeout_ms(), false);
}
#endif  // defined(OS_WIN)
<|endoftext|>


<commit_before>//===--- ToolChains.cpp - ToolChain Implementations -----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "ToolChains.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Version.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/PathV1.h"

// Include the necessary headers to interface with the Windows registry and
// environment.
#ifdef _MSC_VER
  #define WIN32_LEAN_AND_MEAN
  #define NOGDI
  #define NOMINMAX
  #include <Windows.h>
#endif

using namespace clang::driver;
using namespace clang::driver::toolchains;
using namespace clang;
using namespace llvm::opt;

Windows::Windows(const Driver &D, const llvm::Triple& Triple,
                 const ArgList &Args)
  : ToolChain(D, Triple, Args) {
}

Tool *Windows::buildLinker() const {
  return new tools::visualstudio::Link(*this);
}

Tool *Windows::buildAssembler() const {
  if (getTriple().getEnvironment() == llvm::Triple::MachO)
    return new tools::darwin::Assemble(*this);
  getDriver().Diag(clang::diag::err_no_external_windows_assembler);
  return NULL;
}

bool Windows::IsIntegratedAssemblerDefault() const {
  return true;
}

bool Windows::IsUnwindTablesDefault() const {
  return getArch() == llvm::Triple::x86_64;
}

bool Windows::isPICDefault() const {
  return getArch() == llvm::Triple::x86_64;
}

bool Windows::isPIEDefault() const {
  return false;
}

bool Windows::isPICDefaultForced() const {
  return getArch() == llvm::Triple::x86_64;
}

// FIXME: This probably should goto to some platform utils place.
#ifdef _MSC_VER

/// \brief Read registry string.
/// This also supports a means to look for high-versioned keys by use
/// of a $VERSION placeholder in the key path.
/// $VERSION in the key path is a placeholder for the version number,
/// causing the highest value path to be searched for and used.
/// I.e. "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
/// There can be additional characters in the component.  Only the numberic
/// characters are compared.
static bool getSystemRegistryString(const char *keyPath, const char *valueName,
                                    char *value, size_t maxLength) {
  HKEY hRootKey = NULL;
  HKEY hKey = NULL;
  const char* subKey = NULL;
  DWORD valueType;
  DWORD valueSize = maxLength - 1;
  long lResult;
  bool returnValue = false;

  if (strncmp(keyPath, "HKEY_CLASSES_ROOT\\", 18) == 0) {
    hRootKey = HKEY_CLASSES_ROOT;
    subKey = keyPath + 18;
  } else if (strncmp(keyPath, "HKEY_USERS\\", 11) == 0) {
    hRootKey = HKEY_USERS;
    subKey = keyPath + 11;
  } else if (strncmp(keyPath, "HKEY_LOCAL_MACHINE\\", 19) == 0) {
    hRootKey = HKEY_LOCAL_MACHINE;
    subKey = keyPath + 19;
  } else if (strncmp(keyPath, "HKEY_CURRENT_USER\\", 18) == 0) {
    hRootKey = HKEY_CURRENT_USER;
    subKey = keyPath + 18;
  } else {
    return false;
  }

  const char *placeHolder = strstr(subKey, "$VERSION");
  char bestName[256];
  bestName[0] = '\0';
  // If we have a $VERSION placeholder, do the highest-version search.
  if (placeHolder) {
    const char *keyEnd = placeHolder - 1;
    const char *nextKey = placeHolder;
    // Find end of previous key.
    while ((keyEnd > subKey) && (*keyEnd != '\\'))
      keyEnd--;
    // Find end of key containing $VERSION.
    while (*nextKey && (*nextKey != '\\'))
      nextKey++;
    size_t partialKeyLength = keyEnd - subKey;
    char partialKey[256];
    if (partialKeyLength > sizeof(partialKey))
      partialKeyLength = sizeof(partialKey);
    strncpy(partialKey, subKey, partialKeyLength);
    partialKey[partialKeyLength] = '\0';
    HKEY hTopKey = NULL;
    lResult = RegOpenKeyEx(hRootKey, partialKey, 0, KEY_READ, &hTopKey);
    if (lResult == ERROR_SUCCESS) {
      char keyName[256];
      int bestIndex = -1;
      double bestValue = 0.0;
      DWORD index, size = sizeof(keyName) - 1;
      for (index = 0; RegEnumKeyEx(hTopKey, index, keyName, &size, NULL,
          NULL, NULL, NULL) == ERROR_SUCCESS; index++) {
        const char *sp = keyName;
        while (*sp && !isDigit(*sp))
          sp++;
        if (!*sp)
          continue;
        const char *ep = sp + 1;
        while (*ep && (isDigit(*ep) || (*ep == '.')))
          ep++;
        char numBuf[32];
        strncpy(numBuf, sp, sizeof(numBuf) - 1);
        numBuf[sizeof(numBuf) - 1] = '\0';
        double value = strtod(numBuf, NULL);
        if (value > bestValue) {
          bestIndex = (int)index;
          bestValue = value;
          strcpy(bestName, keyName);
        }
        size = sizeof(keyName) - 1;
      }
      // If we found the highest versioned key, open the key and get the value.
      if (bestIndex != -1) {
        // Append rest of key.
        strncat(bestName, nextKey, sizeof(bestName) - 1);
        bestName[sizeof(bestName) - 1] = '\0';
        // Open the chosen key path remainder.
        lResult = RegOpenKeyEx(hTopKey, bestName, 0, KEY_READ, &hKey);
        if (lResult == ERROR_SUCCESS) {
          lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType,
            (LPBYTE)value, &valueSize);
          if (lResult == ERROR_SUCCESS)
            returnValue = true;
          RegCloseKey(hKey);
        }
      }
      RegCloseKey(hTopKey);
    }
  } else {
    lResult = RegOpenKeyEx(hRootKey, subKey, 0, KEY_READ, &hKey);
    if (lResult == ERROR_SUCCESS) {
      lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType,
        (LPBYTE)value, &valueSize);
      if (lResult == ERROR_SUCCESS)
        returnValue = true;
      RegCloseKey(hKey);
    }
  }
  return returnValue;
}

/// \brief Get Windows SDK installation directory.
static bool getWindowsSDKDir(std::string &path) {
  char windowsSDKInstallDir[256];
  // Try the Windows registry.
  bool hasSDKDir = getSystemRegistryString(
   "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
                                           "InstallationFolder",
                                           windowsSDKInstallDir,
                                           sizeof(windowsSDKInstallDir) - 1);
    // If we have both vc80 and vc90, pick version we were compiled with.
  if (hasSDKDir && windowsSDKInstallDir[0]) {
    path = windowsSDKInstallDir;
    return true;
  }
  return false;
}

  // Get Visual Studio installation directory.
static bool getVisualStudioDir(std::string &path) {
  // First check the environment variables that vsvars32.bat sets.
  const char* vcinstalldir = getenv("VCINSTALLDIR");
  if (vcinstalldir) {
    char *p = const_cast<char *>(strstr(vcinstalldir, "\\VC"));
    if (p)
      *p = '\0';
    path = vcinstalldir;
    return true;
  }

  char vsIDEInstallDir[256];
  char vsExpressIDEInstallDir[256];
  // Then try the windows registry.
  bool hasVCDir = getSystemRegistryString(
    "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION",
    "InstallDir", vsIDEInstallDir, sizeof(vsIDEInstallDir) - 1);
  bool hasVCExpressDir = getSystemRegistryString(
    "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\$VERSION",
    "InstallDir", vsExpressIDEInstallDir, sizeof(vsExpressIDEInstallDir) - 1);
    // If we have both vc80 and vc90, pick version we were compiled with.
  if (hasVCDir && vsIDEInstallDir[0]) {
    char *p = (char*)strstr(vsIDEInstallDir, "\\Common7\\IDE");
    if (p)
      *p = '\0';
    path = vsIDEInstallDir;
    return true;
  }

  if (hasVCExpressDir && vsExpressIDEInstallDir[0]) {
    char *p = (char*)strstr(vsExpressIDEInstallDir, "\\Common7\\IDE");
    if (p)
      *p = '\0';
    path = vsExpressIDEInstallDir;
    return true;
  }

  // Try the environment.
  const char *vs100comntools = getenv("VS100COMNTOOLS");
  const char *vs90comntools = getenv("VS90COMNTOOLS");
  const char *vs80comntools = getenv("VS80COMNTOOLS");
  const char *vscomntools = NULL;

  // Try to find the version that we were compiled with
  if(false) {}
  #if (_MSC_VER >= 1600)  // VC100
  else if(vs100comntools) {
    vscomntools = vs100comntools;
  }
  #elif (_MSC_VER == 1500) // VC80
  else if(vs90comntools) {
    vscomntools = vs90comntools;
  }
  #elif (_MSC_VER == 1400) // VC80
  else if(vs80comntools) {
    vscomntools = vs80comntools;
  }
  #endif
  // Otherwise find any version we can
  else if (vs100comntools)
    vscomntools = vs100comntools;
  else if (vs90comntools)
    vscomntools = vs90comntools;
  else if (vs80comntools)
    vscomntools = vs80comntools;

  if (vscomntools && *vscomntools) {
    const char *p = strstr(vscomntools, "\\Common7\\Tools");
    path = p ? std::string(vscomntools, p) : vscomntools;
    return true;
  }
  return false;
}

#endif // _MSC_VER

void Windows::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
                                        ArgStringList &CC1Args) const {
  if (DriverArgs.hasArg(options::OPT_nostdinc))
    return;

  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
    llvm::sys::Path P(getDriver().ResourceDir);
    P.appendComponent("include");
    addSystemInclude(DriverArgs, CC1Args, P.str());
  }

  if (DriverArgs.hasArg(options::OPT_nostdlibinc))
    return;

#ifdef _MSC_VER
  // Honor %INCLUDE%. It should know essential search paths with vcvarsall.bat.
  if (const char *cl_include_dir = getenv("INCLUDE")) {
    SmallVector<StringRef, 8> Dirs;
    StringRef(cl_include_dir).split(Dirs, ";");
    int n = 0;
    for (SmallVectorImpl<StringRef>::iterator I = Dirs.begin(), E = Dirs.end();
         I != E; ++I) {
      StringRef d = *I;
      if (d.size() == 0)
        continue;
      ++n;
      addSystemInclude(DriverArgs, CC1Args, d);
    }
    if (n) return;
  }

  std::string VSDir;
  std::string WindowsSDKDir;

  // When built with access to the proper Windows APIs, try to actually find
  // the correct include paths first.
  if (getVisualStudioDir(VSDir)) {
    addSystemInclude(DriverArgs, CC1Args, VSDir + "\\VC\\include");
    if (getWindowsSDKDir(WindowsSDKDir))
      addSystemInclude(DriverArgs, CC1Args, WindowsSDKDir + "\\include");
    else
      addSystemInclude(DriverArgs, CC1Args,
                       VSDir + "\\VC\\PlatformSDK\\Include");
    return;
  }
#endif // _MSC_VER

  // As a fallback, select default install paths.
  const StringRef Paths[] = {
    "C:/Program Files/Microsoft Visual Studio 10.0/VC/include",
    "C:/Program Files/Microsoft Visual Studio 9.0/VC/include",
    "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
    "C:/Program Files/Microsoft Visual Studio 8/VC/include",
    "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include"
  };
  addSystemIncludes(DriverArgs, CC1Args, Paths);
}

void Windows::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
                                           ArgStringList &CC1Args) const {
  // FIXME: There should probably be logic here to find libc++ on Windows.
}
<commit_msg>Remove PathV1.h use from WindowsToolChain.cpp.<commit_after>//===--- ToolChains.cpp - ToolChain Implementations -----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "ToolChains.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Version.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Path.h"

// Include the necessary headers to interface with the Windows registry and
// environment.
#ifdef _MSC_VER
  #define WIN32_LEAN_AND_MEAN
  #define NOGDI
  #define NOMINMAX
  #include <Windows.h>
#endif

using namespace clang::driver;
using namespace clang::driver::toolchains;
using namespace clang;
using namespace llvm::opt;

Windows::Windows(const Driver &D, const llvm::Triple& Triple,
                 const ArgList &Args)
  : ToolChain(D, Triple, Args) {
}

Tool *Windows::buildLinker() const {
  return new tools::visualstudio::Link(*this);
}

Tool *Windows::buildAssembler() const {
  if (getTriple().getEnvironment() == llvm::Triple::MachO)
    return new tools::darwin::Assemble(*this);
  getDriver().Diag(clang::diag::err_no_external_windows_assembler);
  return NULL;
}

bool Windows::IsIntegratedAssemblerDefault() const {
  return true;
}

bool Windows::IsUnwindTablesDefault() const {
  return getArch() == llvm::Triple::x86_64;
}

bool Windows::isPICDefault() const {
  return getArch() == llvm::Triple::x86_64;
}

bool Windows::isPIEDefault() const {
  return false;
}

bool Windows::isPICDefaultForced() const {
  return getArch() == llvm::Triple::x86_64;
}

// FIXME: This probably should goto to some platform utils place.
#ifdef _MSC_VER

/// \brief Read registry string.
/// This also supports a means to look for high-versioned keys by use
/// of a $VERSION placeholder in the key path.
/// $VERSION in the key path is a placeholder for the version number,
/// causing the highest value path to be searched for and used.
/// I.e. "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
/// There can be additional characters in the component.  Only the numberic
/// characters are compared.
static bool getSystemRegistryString(const char *keyPath, const char *valueName,
                                    char *value, size_t maxLength) {
  HKEY hRootKey = NULL;
  HKEY hKey = NULL;
  const char* subKey = NULL;
  DWORD valueType;
  DWORD valueSize = maxLength - 1;
  long lResult;
  bool returnValue = false;

  if (strncmp(keyPath, "HKEY_CLASSES_ROOT\\", 18) == 0) {
    hRootKey = HKEY_CLASSES_ROOT;
    subKey = keyPath + 18;
  } else if (strncmp(keyPath, "HKEY_USERS\\", 11) == 0) {
    hRootKey = HKEY_USERS;
    subKey = keyPath + 11;
  } else if (strncmp(keyPath, "HKEY_LOCAL_MACHINE\\", 19) == 0) {
    hRootKey = HKEY_LOCAL_MACHINE;
    subKey = keyPath + 19;
  } else if (strncmp(keyPath, "HKEY_CURRENT_USER\\", 18) == 0) {
    hRootKey = HKEY_CURRENT_USER;
    subKey = keyPath + 18;
  } else {
    return false;
  }

  const char *placeHolder = strstr(subKey, "$VERSION");
  char bestName[256];
  bestName[0] = '\0';
  // If we have a $VERSION placeholder, do the highest-version search.
  if (placeHolder) {
    const char *keyEnd = placeHolder - 1;
    const char *nextKey = placeHolder;
    // Find end of previous key.
    while ((keyEnd > subKey) && (*keyEnd != '\\'))
      keyEnd--;
    // Find end of key containing $VERSION.
    while (*nextKey && (*nextKey != '\\'))
      nextKey++;
    size_t partialKeyLength = keyEnd - subKey;
    char partialKey[256];
    if (partialKeyLength > sizeof(partialKey))
      partialKeyLength = sizeof(partialKey);
    strncpy(partialKey, subKey, partialKeyLength);
    partialKey[partialKeyLength] = '\0';
    HKEY hTopKey = NULL;
    lResult = RegOpenKeyEx(hRootKey, partialKey, 0, KEY_READ, &hTopKey);
    if (lResult == ERROR_SUCCESS) {
      char keyName[256];
      int bestIndex = -1;
      double bestValue = 0.0;
      DWORD index, size = sizeof(keyName) - 1;
      for (index = 0; RegEnumKeyEx(hTopKey, index, keyName, &size, NULL,
          NULL, NULL, NULL) == ERROR_SUCCESS; index++) {
        const char *sp = keyName;
        while (*sp && !isDigit(*sp))
          sp++;
        if (!*sp)
          continue;
        const char *ep = sp + 1;
        while (*ep && (isDigit(*ep) || (*ep == '.')))
          ep++;
        char numBuf[32];
        strncpy(numBuf, sp, sizeof(numBuf) - 1);
        numBuf[sizeof(numBuf) - 1] = '\0';
        double value = strtod(numBuf, NULL);
        if (value > bestValue) {
          bestIndex = (int)index;
          bestValue = value;
          strcpy(bestName, keyName);
        }
        size = sizeof(keyName) - 1;
      }
      // If we found the highest versioned key, open the key and get the value.
      if (bestIndex != -1) {
        // Append rest of key.
        strncat(bestName, nextKey, sizeof(bestName) - 1);
        bestName[sizeof(bestName) - 1] = '\0';
        // Open the chosen key path remainder.
        lResult = RegOpenKeyEx(hTopKey, bestName, 0, KEY_READ, &hKey);
        if (lResult == ERROR_SUCCESS) {
          lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType,
            (LPBYTE)value, &valueSize);
          if (lResult == ERROR_SUCCESS)
            returnValue = true;
          RegCloseKey(hKey);
        }
      }
      RegCloseKey(hTopKey);
    }
  } else {
    lResult = RegOpenKeyEx(hRootKey, subKey, 0, KEY_READ, &hKey);
    if (lResult == ERROR_SUCCESS) {
      lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType,
        (LPBYTE)value, &valueSize);
      if (lResult == ERROR_SUCCESS)
        returnValue = true;
      RegCloseKey(hKey);
    }
  }
  return returnValue;
}

/// \brief Get Windows SDK installation directory.
static bool getWindowsSDKDir(std::string &path) {
  char windowsSDKInstallDir[256];
  // Try the Windows registry.
  bool hasSDKDir = getSystemRegistryString(
   "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
                                           "InstallationFolder",
                                           windowsSDKInstallDir,
                                           sizeof(windowsSDKInstallDir) - 1);
    // If we have both vc80 and vc90, pick version we were compiled with.
  if (hasSDKDir && windowsSDKInstallDir[0]) {
    path = windowsSDKInstallDir;
    return true;
  }
  return false;
}

  // Get Visual Studio installation directory.
static bool getVisualStudioDir(std::string &path) {
  // First check the environment variables that vsvars32.bat sets.
  const char* vcinstalldir = getenv("VCINSTALLDIR");
  if (vcinstalldir) {
    char *p = const_cast<char *>(strstr(vcinstalldir, "\\VC"));
    if (p)
      *p = '\0';
    path = vcinstalldir;
    return true;
  }

  char vsIDEInstallDir[256];
  char vsExpressIDEInstallDir[256];
  // Then try the windows registry.
  bool hasVCDir = getSystemRegistryString(
    "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION",
    "InstallDir", vsIDEInstallDir, sizeof(vsIDEInstallDir) - 1);
  bool hasVCExpressDir = getSystemRegistryString(
    "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\$VERSION",
    "InstallDir", vsExpressIDEInstallDir, sizeof(vsExpressIDEInstallDir) - 1);
    // If we have both vc80 and vc90, pick version we were compiled with.
  if (hasVCDir && vsIDEInstallDir[0]) {
    char *p = (char*)strstr(vsIDEInstallDir, "\\Common7\\IDE");
    if (p)
      *p = '\0';
    path = vsIDEInstallDir;
    return true;
  }

  if (hasVCExpressDir && vsExpressIDEInstallDir[0]) {
    char *p = (char*)strstr(vsExpressIDEInstallDir, "\\Common7\\IDE");
    if (p)
      *p = '\0';
    path = vsExpressIDEInstallDir;
    return true;
  }

  // Try the environment.
  const char *vs100comntools = getenv("VS100COMNTOOLS");
  const char *vs90comntools = getenv("VS90COMNTOOLS");
  const char *vs80comntools = getenv("VS80COMNTOOLS");
  const char *vscomntools = NULL;

  // Try to find the version that we were compiled with
  if(false) {}
  #if (_MSC_VER >= 1600)  // VC100
  else if(vs100comntools) {
    vscomntools = vs100comntools;
  }
  #elif (_MSC_VER == 1500) // VC80
  else if(vs90comntools) {
    vscomntools = vs90comntools;
  }
  #elif (_MSC_VER == 1400) // VC80
  else if(vs80comntools) {
    vscomntools = vs80comntools;
  }
  #endif
  // Otherwise find any version we can
  else if (vs100comntools)
    vscomntools = vs100comntools;
  else if (vs90comntools)
    vscomntools = vs90comntools;
  else if (vs80comntools)
    vscomntools = vs80comntools;

  if (vscomntools && *vscomntools) {
    const char *p = strstr(vscomntools, "\\Common7\\Tools");
    path = p ? std::string(vscomntools, p) : vscomntools;
    return true;
  }
  return false;
}

#endif // _MSC_VER

void Windows::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
                                        ArgStringList &CC1Args) const {
  if (DriverArgs.hasArg(options::OPT_nostdinc))
    return;

  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
    SmallString<128> P(getDriver().ResourceDir);
    llvm::sys::path::append(P, "include");
    addSystemInclude(DriverArgs, CC1Args, P.str());
  }

  if (DriverArgs.hasArg(options::OPT_nostdlibinc))
    return;

#ifdef _MSC_VER
  // Honor %INCLUDE%. It should know essential search paths with vcvarsall.bat.
  if (const char *cl_include_dir = getenv("INCLUDE")) {
    SmallVector<StringRef, 8> Dirs;
    StringRef(cl_include_dir).split(Dirs, ";");
    int n = 0;
    for (SmallVectorImpl<StringRef>::iterator I = Dirs.begin(), E = Dirs.end();
         I != E; ++I) {
      StringRef d = *I;
      if (d.size() == 0)
        continue;
      ++n;
      addSystemInclude(DriverArgs, CC1Args, d);
    }
    if (n) return;
  }

  std::string VSDir;
  std::string WindowsSDKDir;

  // When built with access to the proper Windows APIs, try to actually find
  // the correct include paths first.
  if (getVisualStudioDir(VSDir)) {
    addSystemInclude(DriverArgs, CC1Args, VSDir + "\\VC\\include");
    if (getWindowsSDKDir(WindowsSDKDir))
      addSystemInclude(DriverArgs, CC1Args, WindowsSDKDir + "\\include");
    else
      addSystemInclude(DriverArgs, CC1Args,
                       VSDir + "\\VC\\PlatformSDK\\Include");
    return;
  }
#endif // _MSC_VER

  // As a fallback, select default install paths.
  const StringRef Paths[] = {
    "C:/Program Files/Microsoft Visual Studio 10.0/VC/include",
    "C:/Program Files/Microsoft Visual Studio 9.0/VC/include",
    "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
    "C:/Program Files/Microsoft Visual Studio 8/VC/include",
    "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include"
  };
  addSystemIncludes(DriverArgs, CC1Args, Paths);
}

void Windows::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
                                           ArgStringList &CC1Args) const {
  // FIXME: There should probably be logic here to find libc++ on Windows.
}
<|endoftext|>


<commit_before>#include "defs.hpp"
#include <Grappa.hpp>
#include <Collective.hpp>
#include <Delegate.hpp>
#include <ParallelLoop.hpp>
#include <GlobalCompletionEvent.hpp>
#include <GlobalHashSet.hpp>
#include <GlobalCounter.hpp>
#include <Array.hpp>

using namespace Grappa;
namespace d = Grappa::delegate;

DECLARE_int64(cc_hash_size);

static graph g;

static GlobalAddress<graphint> colors;
static GlobalAddress<graphint> visited;
static GlobalAddress<color_t> marks;
static bool changed;
static graphint ncomponents;

struct Edge {
  graphint start, end;
  bool operator==(const Edge& e) const { return e.start == start && e.end == end; }
  friend std::ostream& operator<<(std::ostream& o, const Edge& e);
};
std::ostream& operator<<(std::ostream& o, const Edge& e) {
  o << "{" << e.start << "," << e.end << "}";
  return o;
}
namespace std {
  template <> struct hash<Edge> {
    typedef size_t result_type;
    typedef Edge argument_type;
    size_t operator()(Edge const & e) const noexcept {
      return static_cast<size_t>(e.start ^ e.end);
    }
  };
}

using EdgeHashSet = GlobalHashSet<Edge>;
static GlobalAddress<EdgeHashSet> component_edges;

template< GlobalCompletionEvent * GCE = &impl::local_gce >
void explore(graphint v, graphint mycolor) {
  if (mycolor < 0) {
    auto claimed = d::call(colors+v, [v](graphint * c){
      if (*c < 0) {
        *c = v;
        return true;
      } else {
        return false;
      }
    });
    if (!claimed) return;
    mycolor = v;
  }

  // visit neighbors of v
  graphint _c[2]; Incoherent<graphint>::RO c(g.edgeStart+v, 2, _c);

  forall_localized_async<GCE>(g.endVertex+c[0], c[1]-c[0], [mycolor](graphint& ev){
    // TODO: make async
    GCE->enroll();
    Core origin = mycore();
    auto colors_ev = colors+ev;
    send_message(colors_ev.core(), [origin,mycolor,colors_ev]{
      auto ec = colors_ev.pointer();
      size_t ev = colors_ev - colors;
      if (*ec < 0) {
        *ec = mycolor;
        publicTask([ev,origin,mycolor]{
          explore<GCE>(ev,mycolor);
          complete(make_global(GCE,origin));
        });
      } else {
        // already had color
        // TODO: avoid spawning task? (i.e. make insert() async)
        privateTask([ec,mycolor,origin]{
          Edge edge = (*ec > mycolor) ? Edge{mycolor,*ec} : Edge{*ec,mycolor};
          component_edges->insert(edge);
          complete(make_global(GCE,origin));
        });
      }
    });
  });
}

graphint dfs(graphint root) {
  graphint mycolor = root;
  // VLOG(0) << "dfs(" << root << ")";
  std::function<bool(graphint)> rec = [&mycolor,&rec](graphint v) {
    bool found = false;
    graphint _c[2]; Incoherent<graphint>::RO c(g.edgeStart+v, 2, _c);
    // VLOG(0) << "rec(" << v << ")[" << c[0] << " - " << c[1] << "]";
    for (graphint i=c[0]; i<c[1]; i++) {
      graphint ev = d::read(g.endVertex+i);
      // VLOG(0) << "[" << i-c[0] << "]: " << ev;
      if (d::read(visited+ev)) {
        mycolor = d::read(colors+ev);
        // VLOG(0) << "  found -> " << mycolor;
        found = true;
        break;
      } else if (rec(ev)) {
        // VLOG(0) << "  found (" << mycolor << ")";
        found = true;
        break;
      }
    }
    return found;
  };

  // CHECK(rec(root));
  return mycolor;
}

template< GlobalCompletionEvent * GCE = &impl::local_gce >
void search(graphint v, graphint mycolor) {
  graphint _c[2]; Incoherent<graphint>::RO c(g.edgeStart+v, 2, _c);
  forall_localized_async<GCE>(g.endVertex+c[0], c[1]-c[0], [mycolor](graphint& ev){
    if (d::fetch_and_add(visited+ev, 1) == 0) {
      d::write(colors+ev, mycolor);
      publicTask<GCE>([ev,mycolor]{ search(ev, mycolor); });
    }
  });
}

void pram_cc() {
  const auto NV = g.numVertices;
  int npass = 0;
  do {
    DVLOG(2) << "npass " << npass;
    call_on_all_cores([]{ changed = false; });

    // Hook
    DVLOG(2) << "hook";
    component_edges->forall_keys([NV](Edge& e){
      graphint i = e.start, j = e.end;
      CHECK_LT(i, NV);
      CHECK_LT(j, NV);
      graphint ci = d::read(colors+e.start),
               cj = d::read(colors+e.end);
      CHECK_LT(ci, NV);
      CHECK_LT(cj, NV);
      bool lchanged = false;

      if ( ci < cj ) {
        lchanged = lchanged || d::call(colors+cj, [ci,cj](graphint* ccj){
          if (*ccj == cj) { *ccj = ci; return true; }
          else { return false; }
        });
      }
      if (!lchanged && cj < ci) {
        lchanged = lchanged || d::call(colors+ci, [ci,cj](graphint* cci){
          if (*cci == ci) { *cci = cj; return true; }
          else { return false; }
        });
      }

      if (lchanged) { changed = true; }
    });

    // Compress
    DVLOG(2) << "compress";
    component_edges->forall_keys([NV](Edge& e){
      auto compress = [NV](graphint i) {
        graphint ci, cci, nc;
        ci = nc = d::read(colors+i);
        CHECK_LT(ci, NV);
        CHECK_LT(nc, NV);
        while ( nc != (cci=d::read(colors+nc)) ) { nc = d::read(colors+cci); CHECK_LT(nc, NV); }
        if (nc != ci) {
          changed = true;
          d::write(colors+i, nc);
        }
      };

      compress(e.start);
      compress(e.end);
    });
    npass++;
  } while (reduce<bool,collective_or>(&changed) == true);

  LOG(INFO) << "cc_pram_passes: " << npass;
}

/// Takes a graph as input and an array with length NV.  The array D will store
/// the coloring of each component.  The coloring will be using vertex IDs and
/// therefore will be an integer between 0 and NV-1.  The function returns the
/// total number of components.
graphint connectedComponents(graph * in_g) {
  double t;
  const auto NV = in_g->numVertices;

  auto _component_edges = EdgeHashSet::create(FLAGS_cc_hash_size);

  auto _colors = global_alloc<graphint>(NV);
  auto _visited = global_alloc<graphint>(NV);
  auto _in_g = *in_g;
  call_on_all_cores([_colors,_visited,_in_g,_component_edges]{
    component_edges = _component_edges;
    colors = _colors;
    visited = _visited;
    g = _in_g;
  });

  ///////////////////////////////////////////////////////////////
  // Find component edges

  t = walltime();
  forall_localized(colors, NV, [](int64_t v, graphint& c){ c = -v-1; });

  forall_localized<&impl::local_gce,256>(colors, NV, [](int64_t v, graphint& c){
    explore(v,c);
  });
  t = walltime() - t;

  LOG(INFO) << "cc_set_size: " << component_edges->size();
  LOG(INFO) << "cc_set_insert_time: " << t;
  if (VLOG_IS_ON(3)) {
    component_edges->forall_keys([](Edge& e){ VLOG(0) << e; });
    VLOG(3) << util::array_str("colors: ", colors, NV, 32);
  }

  ///////////////////////////////////////////////////////////////
  // Run classic Connected Components algorithm on reduced graph
  t = walltime();
  pram_cc();
  t = walltime() - t;
  LOG(INFO) << "cc_reduced_graph_time: " << t;

  ///////////////////////////////////////////////////////////////
  // Propagate colors out to the rest of the vertices

  t = walltime();
  Grappa::memset(visited, 0, NV);
  component_edges->forall_keys([](Edge& e){
    auto mycolor = d::read(colors+e.start);
    for (auto ev : {e.start, e.end}) {
      publicTask([ev,mycolor]{
        if (d::fetch_and_add(visited+ev, 1) == 0) {
          search(ev,mycolor);
        }
      });
    }
  });
  t = walltime() - t;
  LOG(INFO) << "cc_propagate_time: " << t;
  DVLOG(3) << util::array_str("colors: ", colors, NV, 32);

  auto nca = GlobalCounter::create();
  forall_localized(colors, NV, [nca](int64_t v, graphint& c){ if (c == v) nca->incr(); });
  graphint ncomponents = nca->count();
  nca->destroy();
  return ncomponents;
}
<commit_msg>CC: allow limiting concurrent roots with: --cc_concurrent_roots<commit_after>#include "defs.hpp"
#include <Grappa.hpp>
#include <Collective.hpp>
#include <Delegate.hpp>
#include <ParallelLoop.hpp>
#include <GlobalCompletionEvent.hpp>
#include <GlobalHashSet.hpp>
#include <GlobalCounter.hpp>
#include <Array.hpp>

using namespace Grappa;
namespace d = Grappa::delegate;

DECLARE_int64(cc_hash_size);
DEFINE_int64(cc_concurrent_roots, 1, "number of concurrent `explores` to have at a given time");

struct Edge {
  graphint start, end;
  bool operator==(const Edge& e) const { return e.start == start && e.end == end; }
  friend std::ostream& operator<<(std::ostream& o, const Edge& e);
};
std::ostream& operator<<(std::ostream& o, const Edge& e) {
  o << "{" << e.start << "," << e.end << "}";
  return o;
}
namespace std {
  template <> struct hash<Edge> {
    typedef size_t result_type;
    typedef Edge argument_type;
    size_t operator()(Edge const & e) const noexcept {
      return static_cast<size_t>(e.start ^ e.end);
    }
  };
}

///////////////////////////////////////////////////////////////
// Globals
static graph g;

static GlobalAddress<graphint> colors;
static GlobalAddress<graphint> visited;
static GlobalAddress<color_t> marks;
static bool changed;
static graphint ncomponents;

static GlobalAddress<GlobalHashSet<Edge>> component_edges;

static GlobalCompletionEvent gce;

///////////////////////////////////////////////////////////////

template< GlobalCompletionEvent * GCE = &impl::local_gce >
void explore(graphint v, graphint mycolor, GlobalAddress<CompletionEvent> owner) {
  if (mycolor < 0) {
    auto claimed = d::call(colors+v, [v](graphint * c){
      if (*c < 0) {
        *c = v;
        return true;
      } else {
        return false;
      }
    });
    if (!claimed) return;
    mycolor = v;
  }

  // visit neighbors of v
  graphint _c[2]; Incoherent<graphint>::RO c(g.edgeStart+v, 2, _c);

  enroll(owner, c[1]-c[0]);
  forall_localized_async<nullptr>(g.endVertex+c[0], c[1]-c[0], [mycolor,owner](graphint& ev){
    // TODO: make async
    Core origin = mycore();
    auto colors_ev = colors+ev;
    send_message(colors_ev.core(), [owner,mycolor,colors_ev]{
      auto ec = colors_ev.pointer();
      size_t ev = colors_ev - colors;
      if (*ec < 0) {
        *ec = mycolor;
        publicTask([ev,mycolor,owner]{
          explore(ev,mycolor,owner);
          complete(owner);
        });
      } else {
        // already had color
        // TODO: avoid spawning task? (i.e. make insert() async)
        privateTask([ec,mycolor,owner]{
          Edge edge = (*ec > mycolor) ? Edge{mycolor,*ec} : Edge{*ec,mycolor};
          component_edges->insert(edge);
          complete(owner);
        });
      }
    });
  });
}

template< GlobalCompletionEvent * GCE = &impl::local_gce >
void search(graphint v, graphint mycolor) {
  graphint _c[2]; Incoherent<graphint>::RO c(g.edgeStart+v, 2, _c);
  forall_localized_async<GCE>(g.endVertex+c[0], c[1]-c[0], [mycolor](graphint& ev){
    if (d::fetch_and_add(visited+ev, 1) == 0) {
      d::write(colors+ev, mycolor);
      publicTask<GCE>([ev,mycolor]{ search(ev, mycolor); });
    }
  });
}

void pram_cc() {
  const auto NV = g.numVertices;
  int npass = 0;
  do {
    DVLOG(2) << "npass " << npass;
    call_on_all_cores([]{ changed = false; });

    // Hook
    DVLOG(2) << "hook";
    component_edges->forall_keys([NV](Edge& e){
      graphint i = e.start, j = e.end;
      CHECK_LT(i, NV);
      CHECK_LT(j, NV);
      graphint ci = d::read(colors+e.start),
               cj = d::read(colors+e.end);
      CHECK_LT(ci, NV);
      CHECK_LT(cj, NV);
      bool lchanged = false;

      if ( ci < cj ) {
        lchanged = lchanged || d::call(colors+cj, [ci,cj](graphint* ccj){
          if (*ccj == cj) { *ccj = ci; return true; }
          else { return false; }
        });
      }
      if (!lchanged && cj < ci) {
        lchanged = lchanged || d::call(colors+ci, [ci,cj](graphint* cci){
          if (*cci == ci) { *cci = cj; return true; }
          else { return false; }
        });
      }

      if (lchanged) { changed = true; }
    });

    // Compress
    DVLOG(2) << "compress";
    component_edges->forall_keys([NV](Edge& e){
      auto compress = [NV](graphint i) {
        graphint ci, cci, nc;
        ci = nc = d::read(colors+i);
        CHECK_LT(ci, NV);
        CHECK_LT(nc, NV);
        while ( nc != (cci=d::read(colors+nc)) ) { nc = d::read(colors+cci); CHECK_LT(nc, NV); }
        if (nc != ci) {
          changed = true;
          d::write(colors+i, nc);
        }
      };

      compress(e.start);
      compress(e.end);
    });
    npass++;
  } while (reduce<bool,collective_or>(&changed) == true);

  LOG(INFO) << "cc_pram_passes: " << npass;
}

/// Takes a graph as input and an array with length NV.  The array D will store
/// the coloring of each component.  The coloring will be using vertex IDs and
/// therefore will be an integer between 0 and NV-1.  The function returns the
/// total number of components.
graphint connectedComponents(graph * in_g) {
  double t;
  const auto NV = in_g->numVertices;

  auto _component_edges = GlobalHashSet<Edge>::create(FLAGS_cc_hash_size);

  auto _colors = global_alloc<graphint>(NV);
  auto _visited = global_alloc<graphint>(NV);
  auto _in_g = *in_g;
  call_on_all_cores([_colors,_visited,_in_g,_component_edges]{
    component_edges = _component_edges;
    colors = _colors;
    visited = _visited;
    g = _in_g;
  });

  ///////////////////////////////////////////////////////////////
  // Find component edges

  t = walltime();
  forall_localized(colors, NV, [](int64_t v, graphint& c){ c = -v-1; });

  size_t current_root = 0;
  auto root_addr = make_global(&current_root);

  // forall_localized<&impl::local_gce,256>(colors, NV, [](int64_t v, graphint& c){
  on_all_cores([root_addr]{
    range_t r = blockDist(0, FLAGS_cc_concurrent_roots, mycore(), cores());
    auto nlocalroots = r.end - r.start;

    for (size_t i = 0; i < nlocalroots; i++) {
      privateTask<&gce>([root_addr]{
        CompletionEvent ce;
        auto cea = make_global(&ce);
        graphint v;
        while ((v=d::fetch_and_add(root_addr,1)) < g.numVertices) {
          explore<nullptr>(v, d::read(colors+v), cea);
          ce.wait();
        }
      });
    }
  });
  gce.wait();

  t = walltime() - t;

  LOG(INFO) << "cc_set_size: " << component_edges->size();
  LOG(INFO) << "cc_set_insert_time: " << t;
  if (VLOG_IS_ON(3)) {
    component_edges->forall_keys([](Edge& e){ VLOG(0) << e; });
    VLOG(3) << util::array_str("colors: ", colors, NV, 32);
  }

  ///////////////////////////////////////////////////////////////
  // Run classic Connected Components algorithm on reduced graph
  t = walltime();
  pram_cc();
  t = walltime() - t;
  LOG(INFO) << "cc_reduced_graph_time: " << t;

  ///////////////////////////////////////////////////////////////
  // Propagate colors out to the rest of the vertices

  t = walltime();
  Grappa::memset(visited, 0, NV);
  component_edges->forall_keys([](Edge& e){
    auto mycolor = d::read(colors+e.start);
    for (auto ev : {e.start, e.end}) {
      publicTask([ev,mycolor]{
        if (d::fetch_and_add(visited+ev, 1) == 0) {
          search(ev,mycolor);
        }
      });
    }
  });
  t = walltime() - t;
  LOG(INFO) << "cc_propagate_time: " << t;
  DVLOG(3) << util::array_str("colors: ", colors, NV, 32);

  auto nca = GlobalCounter::create();
  forall_localized(colors, NV, [nca](int64_t v, graphint& c){ if (c == v) nca->incr(); });
  graphint ncomponents = nca->count();
  nca->destroy();
  return ncomponents;
}
<|endoftext|>