<commit_before>// Copyright 2016 Benjamin Glatzel
//
// 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.

// Precompiled header file
#include "stdafx_vulkan.h"
#include "stdafx.h"

namespace Intrinsic
{
namespace Renderer
{
namespace Vulkan
{
namespace RenderPass
{
namespace
{
Resources::ImageRef _lightingBufferImageRef;
Resources::ImageRef _lightingBufferTransparentsImageRef;
Resources::FramebufferRef _framebufferRef;
Resources::FramebufferRef _framebufferTransparentsRef;
Resources::RenderPassRef _renderPassRef;
Resources::PipelineRef _pipelineRef;
Resources::DrawCallRef _drawCallRef;
Resources::DrawCallRef _drawCallTransparentsRef;

// <-

struct PerInstanceData
{
  glm::mat4 viewMatrix;
  glm::mat4 invProjectionMatrix;
  glm::mat4 invViewMatrix;

  glm::mat4 shadowViewProjMatrix[_INTR_MAX_SHADOW_MAP_COUNT];
} _perInstanceData;

// <-

void renderLighting(Resources::FramebufferRef p_FramebufferRef,
                    Resources::DrawCallRef p_DrawCall,
                    Resources::ImageRef p_LightingBufferRef,
                    Components::CameraRef p_CameraRef)
{
  using namespace Resources;

  // Update per instance data
  {
    _perInstanceData.invProjectionMatrix =
        Components::CameraManager::_inverseProjectionMatrix(p_CameraRef);
    _perInstanceData.viewMatrix =
        Components::CameraManager::_viewMatrix(p_CameraRef);
    _perInstanceData.invViewMatrix =
        Components::CameraManager::_inverseViewMatrix(p_CameraRef);

    const _INTR_ARRAY(Core::Resources::FrustumRef)& shadowFrustums =
        RenderProcess::Default::_shadowFrustums[p_CameraRef];

    for (uint32_t i = 0u; i < shadowFrustums.size(); ++i)
    {
      Core::Resources::FrustumRef shadowFrustumRef = shadowFrustums[i];

      // Transform from camera view space => light proj. space
      _perInstanceData.shadowViewProjMatrix[i] =
          Core::Resources::FrustumManager::_viewProjectionMatrix(
              shadowFrustumRef) *
          Components::CameraManager::_inverseViewMatrix(p_CameraRef);
    }

    DrawCallRefArray dcsToUpdate = {p_DrawCall};
    DrawCallManager::allocateAndUpdateUniformMemory(
        dcsToUpdate, nullptr, 0u, &_perInstanceData, sizeof(PerInstanceData));
  }

  VkCommandBuffer primaryCmdBuffer = RenderSystem::getPrimaryCommandBuffer();

  ImageManager::insertImageMemoryBarrier(
      p_LightingBufferRef, VK_IMAGE_LAYOUT_UNDEFINED,
      VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);

  RenderSystem::beginRenderPass(_renderPassRef, p_FramebufferRef,
                                VK_SUBPASS_CONTENTS_INLINE);
  {
    RenderSystem::dispatchDrawCall(p_DrawCall, primaryCmdBuffer);
  }
  RenderSystem::endRenderPass(_renderPassRef);

  ImageManager::insertImageMemoryBarrier(
      p_LightingBufferRef, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
      VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
}

void Lighting::init()
{
  using namespace Resources;

  PipelineRefArray pipelinesToCreate;
  PipelineLayoutRefArray pipelineLayoutsToCreate;
  RenderPassRefArray renderpassesToCreate;

  // Pipeline layout
  PipelineLayoutRef pipelineLayout;
  {
    pipelineLayout = PipelineLayoutManager::createPipelineLayout(_N(Lighting));
    PipelineLayoutManager::resetToDefault(pipelineLayout);

    GpuProgramManager::reflectPipelineLayout(
        8u, {Resources::GpuProgramManager::getResourceByName("lighting.frag")},
        pipelineLayout);
  }
  pipelineLayoutsToCreate.push_back(pipelineLayout);

  // Render passes
  {
    _renderPassRef = RenderPassManager::createRenderPass(_N(Lighting));
    RenderPassManager::resetToDefault(_renderPassRef);

    AttachmentDescription colorAttachment = {Format::kR16G16B16A16Float, 0u};

    RenderPassManager::_descAttachments(_renderPassRef)
        .push_back(colorAttachment);
  }
  renderpassesToCreate.push_back(_renderPassRef);

  // Pipelines
  {
    _pipelineRef = PipelineManager::createPipeline(_N(Lighting));
    PipelineManager::resetToDefault(_pipelineRef);

    PipelineManager::_descFragmentProgram(_pipelineRef) =
        GpuProgramManager::getResourceByName("lighting.frag");
    PipelineManager::_descVertexProgram(_pipelineRef) =
        GpuProgramManager::getResourceByName("fullscreen_triangle.vert");
    PipelineManager::_descRenderPass(_pipelineRef) = _renderPassRef;
    PipelineManager::_descPipelineLayout(_pipelineRef) = pipelineLayout;
    PipelineManager::_descVertexLayout(_pipelineRef) = Dod::Ref();
    PipelineManager::_descDepthStencilState(_pipelineRef) =
        DepthStencilStates::kDefaultNoDepthTestAndWrite;
  }
  pipelinesToCreate.push_back(_pipelineRef);

  PipelineLayoutManager::createResources(pipelineLayoutsToCreate);
  RenderPassManager::createResources(renderpassesToCreate);
  PipelineManager::createResources(pipelinesToCreate);
}

// <-

void Lighting::onReinitRendering()
{
  using namespace Resources;

  ImageRefArray imgsToDestroy;
  ImageRefArray imgsToCreate;
  FramebufferRefArray framebuffersToDestroy;
  FramebufferRefArray framebuffersToCreate;
  DrawCallRefArray drawCallsToDestroy;
  DrawCallRefArray drawcallsToCreate;

  // Cleanup old resources
  {
    if (_drawCallRef.isValid())
      drawCallsToDestroy.push_back(_drawCallRef);
    if (_drawCallTransparentsRef.isValid())
      drawCallsToDestroy.push_back(_drawCallTransparentsRef);

    if (_framebufferRef.isValid())
      framebuffersToDestroy.push_back(_framebufferRef);
    if (_framebufferTransparentsRef.isValid())
      framebuffersToDestroy.push_back(_framebufferTransparentsRef);

    if (_lightingBufferImageRef.isValid())
      imgsToDestroy.push_back(_lightingBufferImageRef);
    if (_lightingBufferTransparentsImageRef.isValid())
      imgsToDestroy.push_back(_lightingBufferTransparentsImageRef);

    FramebufferManager::destroyFramebuffersAndResources(framebuffersToDestroy);
    DrawCallManager::destroyDrawCallsAndResources(drawCallsToDestroy);
    ImageManager::destroyImagesAndResources(imgsToDestroy);
  }

  glm::uvec3 dim = glm::uvec3(RenderSystem::_backbufferDimensions.x,
                              RenderSystem::_backbufferDimensions.y, 1u);

  _lightingBufferImageRef = ImageManager::createImage(_N(LightBuffer));
  {
    ImageManager::resetToDefault(_lightingBufferImageRef);
    ImageManager::addResourceFlags(
        _lightingBufferImageRef,
        Dod::Resources::ResourceFlags::kResourceVolatile);
    ImageManager::_descMemoryPoolType(_lightingBufferImageRef) =
        MemoryPoolType::kResolutionDependentImages;

    ImageManager::_descDimensions(_lightingBufferImageRef) = dim;
    ImageManager::_descImageFormat(_lightingBufferImageRef) =
        Format::kR16G16B16A16Float;
    ImageManager::_descImageType(_lightingBufferImageRef) = ImageType::kTexture;
  }
  imgsToCreate.push_back(_lightingBufferImageRef);

  _lightingBufferTransparentsImageRef =
      ImageManager::createImage(_N(LightBufferTransparents));
  {
    ImageManager::resetToDefault(_lightingBufferTransparentsImageRef);
    ImageManager::addResourceFlags(
        _lightingBufferTransparentsImageRef,
        Dod::Resources::ResourceFlags::kResourceVolatile);
    ImageManager::_descMemoryPoolType(_lightingBufferTransparentsImageRef) =
        MemoryPoolType::kResolutionDependentImages;

    ImageManager::_descDimensions(_lightingBufferTransparentsImageRef) = dim;
    ImageManager::_descImageFormat(_lightingBufferTransparentsImageRef) =
        Format::kR16G16B16A16Float;
    ImageManager::_descImageType(_lightingBufferTransparentsImageRef) =
        ImageType::kTexture;
  }
  imgsToCreate.push_back(_lightingBufferTransparentsImageRef);

  ImageManager::createResources(imgsToCreate);

  _framebufferRef = FramebufferManager::createFramebuffer(_N(Lighting));
  {
    FramebufferManager::resetToDefault(_framebufferRef);
    FramebufferManager::addResourceFlags(
        _framebufferRef, Dod::Resources::ResourceFlags::kResourceVolatile);

    FramebufferManager::_descAttachedImages(_framebufferRef)
        .push_back(_lightingBufferImageRef);

    FramebufferManager::_descDimensions(_framebufferRef) =
        glm::uvec2(RenderSystem::_backbufferDimensions.x,
                   RenderSystem::_backbufferDimensions.y);
    FramebufferManager::_descRenderPass(_framebufferRef) = _renderPassRef;

    framebuffersToCreate.push_back(_framebufferRef);
  }

  _framebufferTransparentsRef =
      FramebufferManager::createFramebuffer(_N(LightingTransparents));
  {
    FramebufferManager::resetToDefault(_framebufferTransparentsRef);
    FramebufferManager::addResourceFlags(
        _framebufferTransparentsRef,
        Dod::Resources::ResourceFlags::kResourceVolatile);

    FramebufferManager::_descAttachedImages(_framebufferTransparentsRef)
        .push_back(_lightingBufferTransparentsImageRef);

    FramebufferManager::_descDimensions(_framebufferTransparentsRef) =
        glm::uvec2(RenderSystem::_backbufferDimensions.x,
                   RenderSystem::_backbufferDimensions.y);
    FramebufferManager::_descRenderPass(_framebufferTransparentsRef) =
        _renderPassRef;

    framebuffersToCreate.push_back(_framebufferTransparentsRef);
  }

  FramebufferManager::createResources(framebuffersToCreate);

  // Draw calls
  _drawCallRef = DrawCallManager::createDrawCall(_N(Lighting));
  {
    DrawCallManager::resetToDefault(_drawCallRef);
    DrawCallManager::addResourceFlags(
        _drawCallRef, Dod::Resources::ResourceFlags::kResourceVolatile);

    DrawCallManager::_descPipeline(_drawCallRef) = _pipelineRef;
    DrawCallManager::_descVertexCount(_drawCallRef) = 3u;

    DrawCallManager::bindBuffer(
        _drawCallRef, _N(PerInstance), GpuProgramType::kFragment,
        UniformManager::_perInstanceUniformBuffer,
        UboType::kPerInstanceFragment, sizeof(PerInstanceData));
    DrawCallManager::bindImage(
        _drawCallRef, _N(albedoTex), GpuProgramType::kFragment,
        ImageManager::getResourceByName(_N(GBufferAlbedo)),
        Samplers::kLinearClamp);
    DrawCallManager::bindImage(
        _drawCallRef, _N(normalTex), GpuProgramType::kFragment,
        ImageManager::getResourceByName(_N(GBufferNormal)),
        Samplers::kLinearClamp);
    DrawCallManager::bindImage(
        _drawCallRef, _N(parameter0Tex), GpuProgramType::kFragment,
        ImageManager::getResourceByName(_N(GBufferParameter0)),
        Samplers::kLinearClamp);
    DrawCallManager::bindImage(
        _drawCallRef, _N(depthTex), GpuProgramType::kFragment,
        ImageManager::getResourceByName(_N(GBufferDepth)),
        Samplers::kNearestClamp);
    DrawCallManager::bindImage(
        _drawCallRef, _N(ssaoTex), GpuProgramType::kFragment,
        ImageManager::getResourceByName(_N(SSAO)), Samplers::kNearestClamp);
    DrawCallManager::bindImage(_drawCallRef, _N(irradianceTex),
                               GpuProgramType::kFragment,
                               ImageManager::getResourceByName(
                                   _N(GCanyon_C_YumaPoint_3k_cube_irradiance)),
                               Samplers::kLinearClamp);
    DrawCallManager::bindImage(_drawCallRef, _N(specularTex),
                               GpuProgramType::kFragment,
                               ImageManager::getResourceByName(
                                   _N(GCanyon_C_YumaPoint_3k_cube_specular)),
                               Samplers::kLinearClamp);
    DrawCallManager::bindImage(
        _drawCallRef, _N(shadowBufferTex), GpuProgramType::kFragment,
        ImageManager::getResourceByName(_N(ShadowBuffer)), Samplers::kShadow);
    DrawCallManager::bindBuffer(
        _drawCallRef, _N(MaterialBuffer), GpuProgramType::kFragment,
        MaterialBuffer::_materialBuffer, UboType::kInvalidUbo,
        BufferManager::_descSizeInBytes(MaterialBuffer::_materialBuffer));
  }

  drawcallsToCreate.push_back(_drawCallRef);

  _drawCallTransparentsRef =
      DrawCallManager::createDrawCall(_N(LightingTransparents));
  {
    DrawCallManager::resetToDefault(_drawCallTransparentsRef);
    DrawCallManager::addResourceFlags(
        _drawCallTransparentsRef,
        Dod::Resources::ResourceFlags::kResourceVolatile);

    DrawCallManager::_descPipeline(_drawCallTransparentsRef) = _pipelineRef;
    DrawCallManager::_descVertexCount(_drawCallTransparentsRef) = 3u;

    DrawCallManager::bindBuffer(
        _drawCallTransparentsRef, _N(PerInstance), GpuProgramType::kFragment,
        UniformManager::_perInstanceUniformBuffer,
        UboType::kPerInstanceFragment, sizeof(PerInstanceData));
    DrawCallManager::bindImage(
        _drawCallTransparentsRef, _N(albedoTex), GpuProgramType::kFragment,
        ImageManager::getResourceByName(_N(GBufferTransparentsAlbedo)),
        Samplers::kLinearClamp);
    DrawCallManager::bindImage(
        _drawCallTransparentsRef, _N(normalTex), GpuProgramType::kFragment,
        ImageManager::getResourceByName(_N(GBufferTransparentsNormal)),
        Samplers::kLinearClamp);
    DrawCallManager::bindImage(
        _drawCallTransparentsRef, _N(parameter0Tex), GpuProgramType::kFragment,
        ImageManager::getResourceByName(_N(GBufferTransparentsParameter0)),
        Samplers::kLinearClamp);
    DrawCallManager::bindImage(
        _drawCallTransparentsRef, _N(depthTex), GpuProgramType::kFragment,
        ImageManager::getResourceByName(_N(GBufferTransparentsDepth)),
        Samplers::kNearestClamp);
    DrawCallManager::bindImage(
        _drawCallTransparentsRef, _N(ssaoTex), GpuProgramType::kFragment,
        ImageManager::getResourceByName(_N(SSAO)), Samplers::kLinearClamp);
    DrawCallManager::bindImage(_drawCallTransparentsRef, _N(irradianceTex),
                               GpuProgramType::kFragment,
                               ImageManager::getResourceByName(
                                   _N(GCanyon_C_YumaPoint_3k_cube_irradiance)),
                               Samplers::kLinearClamp);
    DrawCallManager::bindImage(_drawCallTransparentsRef, _N(specularTex),
                               GpuProgramType::kFragment,
                               ImageManager::getResourceByName(
                                   _N(GCanyon_C_YumaPoint_3k_cube_specular)),
                               Samplers::kLinearClamp);
    DrawCallManager::bindImage(
        _drawCallTransparentsRef, _N(shadowBufferTex),
        GpuProgramType::kFragment,
        ImageManager::getResourceByName(_N(ShadowBuffer)), Samplers::kShadow);
    DrawCallManager::bindBuffer(
        _drawCallTransparentsRef, _N(MaterialBuffer), GpuProgramType::kFragment,
        MaterialBuffer::_materialBuffer, UboType::kInvalidUbo,
        BufferManager::_descSizeInBytes(MaterialBuffer::_materialBuffer));
  }
  drawcallsToCreate.push_back(_drawCallTransparentsRef);

  DrawCallManager::createResources(drawcallsToCreate);
}

// <-

void Lighting::destroy() {}

// <-

void Lighting::render(float p_DeltaT, Components::CameraRef p_CameraRef)
{
  _INTR_PROFILE_CPU("Render Pass", "Render Lighting");
  _INTR_PROFILE_GPU("Render Lighting");

  renderLighting(_framebufferRef, _drawCallRef, _lightingBufferImageRef,
                 p_CameraRef);
  renderLighting(_framebufferTransparentsRef, _drawCallTransparentsRef,
                 _lightingBufferTransparentsImageRef, p_CameraRef);
}
}
}
}
}
<commit_msg>Sample linearly in the lighting pass<commit_after>// Copyright 2016 Benjamin Glatzel
//
// 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.

// Precompiled header file
#include "stdafx_vulkan.h"
#include "stdafx.h"

namespace Intrinsic
{
namespace Renderer
{
namespace Vulkan
{
namespace RenderPass
{
namespace
{
Resources::ImageRef _lightingBufferImageRef;
Resources::ImageRef _lightingBufferTransparentsImageRef;
Resources::FramebufferRef _framebufferRef;
Resources::FramebufferRef _framebufferTransparentsRef;
Resources::RenderPassRef _renderPassRef;
Resources::PipelineRef _pipelineRef;
Resources::DrawCallRef _drawCallRef;
Resources::DrawCallRef _drawCallTransparentsRef;

// <-

struct PerInstanceData
{
  glm::mat4 viewMatrix;
  glm::mat4 invProjectionMatrix;
  glm::mat4 invViewMatrix;

  glm::mat4 shadowViewProjMatrix[_INTR_MAX_SHADOW_MAP_COUNT];
} _perInstanceData;

// <-

void renderLighting(Resources::FramebufferRef p_FramebufferRef,
                    Resources::DrawCallRef p_DrawCall,
                    Resources::ImageRef p_LightingBufferRef,
                    Components::CameraRef p_CameraRef)
{
  using namespace Resources;

  // Update per instance data
  {
    _perInstanceData.invProjectionMatrix =
        Components::CameraManager::_inverseProjectionMatrix(p_CameraRef);
    _perInstanceData.viewMatrix =
        Components::CameraManager::_viewMatrix(p_CameraRef);
    _perInstanceData.invViewMatrix =
        Components::CameraManager::_inverseViewMatrix(p_CameraRef);

    const _INTR_ARRAY(Core::Resources::FrustumRef)& shadowFrustums =
        RenderProcess::Default::_shadowFrustums[p_CameraRef];

    for (uint32_t i = 0u; i < shadowFrustums.size(); ++i)
    {
      Core::Resources::FrustumRef shadowFrustumRef = shadowFrustums[i];

      // Transform from camera view space => light proj. space
      _perInstanceData.shadowViewProjMatrix[i] =
          Core::Resources::FrustumManager::_viewProjectionMatrix(
              shadowFrustumRef) *
          Components::CameraManager::_inverseViewMatrix(p_CameraRef);
    }

    DrawCallRefArray dcsToUpdate = {p_DrawCall};
    DrawCallManager::allocateAndUpdateUniformMemory(
        dcsToUpdate, nullptr, 0u, &_perInstanceData, sizeof(PerInstanceData));
  }

  VkCommandBuffer primaryCmdBuffer = RenderSystem::getPrimaryCommandBuffer();

  ImageManager::insertImageMemoryBarrier(
      p_LightingBufferRef, VK_IMAGE_LAYOUT_UNDEFINED,
      VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);

  RenderSystem::beginRenderPass(_renderPassRef, p_FramebufferRef,
                                VK_SUBPASS_CONTENTS_INLINE);
  {
    RenderSystem::dispatchDrawCall(p_DrawCall, primaryCmdBuffer);
  }
  RenderSystem::endRenderPass(_renderPassRef);

  ImageManager::insertImageMemoryBarrier(
      p_LightingBufferRef, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
      VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
}

void Lighting::init()
{
  using namespace Resources;

  PipelineRefArray pipelinesToCreate;
  PipelineLayoutRefArray pipelineLayoutsToCreate;
  RenderPassRefArray renderpassesToCreate;

  // Pipeline layout
  PipelineLayoutRef pipelineLayout;
  {
    pipelineLayout = PipelineLayoutManager::createPipelineLayout(_N(Lighting));
    PipelineLayoutManager::resetToDefault(pipelineLayout);

    GpuProgramManager::reflectPipelineLayout(
        8u, {Resources::GpuProgramManager::getResourceByName("lighting.frag")},
        pipelineLayout);
  }
  pipelineLayoutsToCreate.push_back(pipelineLayout);

  // Render passes
  {
    _renderPassRef = RenderPassManager::createRenderPass(_N(Lighting));
    RenderPassManager::resetToDefault(_renderPassRef);

    AttachmentDescription colorAttachment = {Format::kR16G16B16A16Float, 0u};

    RenderPassManager::_descAttachments(_renderPassRef)
        .push_back(colorAttachment);
  }
  renderpassesToCreate.push_back(_renderPassRef);

  // Pipelines
  {
    _pipelineRef = PipelineManager::createPipeline(_N(Lighting));
    PipelineManager::resetToDefault(_pipelineRef);

    PipelineManager::_descFragmentProgram(_pipelineRef) =
        GpuProgramManager::getResourceByName("lighting.frag");
    PipelineManager::_descVertexProgram(_pipelineRef) =
        GpuProgramManager::getResourceByName("fullscreen_triangle.vert");
    PipelineManager::_descRenderPass(_pipelineRef) = _renderPassRef;
    PipelineManager::_descPipelineLayout(_pipelineRef) = pipelineLayout;
    PipelineManager::_descVertexLayout(_pipelineRef) = Dod::Ref();
    PipelineManager::_descDepthStencilState(_pipelineRef) =
        DepthStencilStates::kDefaultNoDepthTestAndWrite;
  }
  pipelinesToCreate.push_back(_pipelineRef);

  PipelineLayoutManager::createResources(pipelineLayoutsToCreate);
  RenderPassManager::createResources(renderpassesToCreate);
  PipelineManager::createResources(pipelinesToCreate);
}

// <-

void Lighting::onReinitRendering()
{
  using namespace Resources;

  ImageRefArray imgsToDestroy;
  ImageRefArray imgsToCreate;
  FramebufferRefArray framebuffersToDestroy;
  FramebufferRefArray framebuffersToCreate;
  DrawCallRefArray drawCallsToDestroy;
  DrawCallRefArray drawcallsToCreate;

  // Cleanup old resources
  {
    if (_drawCallRef.isValid())
      drawCallsToDestroy.push_back(_drawCallRef);
    if (_drawCallTransparentsRef.isValid())
      drawCallsToDestroy.push_back(_drawCallTransparentsRef);

    if (_framebufferRef.isValid())
      framebuffersToDestroy.push_back(_framebufferRef);
    if (_framebufferTransparentsRef.isValid())
      framebuffersToDestroy.push_back(_framebufferTransparentsRef);

    if (_lightingBufferImageRef.isValid())
      imgsToDestroy.push_back(_lightingBufferImageRef);
    if (_lightingBufferTransparentsImageRef.isValid())
      imgsToDestroy.push_back(_lightingBufferTransparentsImageRef);

    FramebufferManager::destroyFramebuffersAndResources(framebuffersToDestroy);
    DrawCallManager::destroyDrawCallsAndResources(drawCallsToDestroy);
    ImageManager::destroyImagesAndResources(imgsToDestroy);
  }

  glm::uvec3 dim = glm::uvec3(RenderSystem::_backbufferDimensions.x,
                              RenderSystem::_backbufferDimensions.y, 1u);

  _lightingBufferImageRef = ImageManager::createImage(_N(LightBuffer));
  {
    ImageManager::resetToDefault(_lightingBufferImageRef);
    ImageManager::addResourceFlags(
        _lightingBufferImageRef,
        Dod::Resources::ResourceFlags::kResourceVolatile);
    ImageManager::_descMemoryPoolType(_lightingBufferImageRef) =
        MemoryPoolType::kResolutionDependentImages;

    ImageManager::_descDimensions(_lightingBufferImageRef) = dim;
    ImageManager::_descImageFormat(_lightingBufferImageRef) =
        Format::kR16G16B16A16Float;
    ImageManager::_descImageType(_lightingBufferImageRef) = ImageType::kTexture;
  }
  imgsToCreate.push_back(_lightingBufferImageRef);

  _lightingBufferTransparentsImageRef =
      ImageManager::createImage(_N(LightBufferTransparents));
  {
    ImageManager::resetToDefault(_lightingBufferTransparentsImageRef);
    ImageManager::addResourceFlags(
        _lightingBufferTransparentsImageRef,
        Dod::Resources::ResourceFlags::kResourceVolatile);
    ImageManager::_descMemoryPoolType(_lightingBufferTransparentsImageRef) =
        MemoryPoolType::kResolutionDependentImages;

    ImageManager::_descDimensions(_lightingBufferTransparentsImageRef) = dim;
    ImageManager::_descImageFormat(_lightingBufferTransparentsImageRef) =
        Format::kR16G16B16A16Float;
    ImageManager::_descImageType(_lightingBufferTransparentsImageRef) =
        ImageType::kTexture;
  }
  imgsToCreate.push_back(_lightingBufferTransparentsImageRef);

  ImageManager::createResources(imgsToCreate);

  _framebufferRef = FramebufferManager::createFramebuffer(_N(Lighting));
  {
    FramebufferManager::resetToDefault(_framebufferRef);
    FramebufferManager::addResourceFlags(
        _framebufferRef, Dod::Resources::ResourceFlags::kResourceVolatile);

    FramebufferManager::_descAttachedImages(_framebufferRef)
        .push_back(_lightingBufferImageRef);

    FramebufferManager::_descDimensions(_framebufferRef) =
        glm::uvec2(RenderSystem::_backbufferDimensions.x,
                   RenderSystem::_backbufferDimensions.y);
    FramebufferManager::_descRenderPass(_framebufferRef) = _renderPassRef;

    framebuffersToCreate.push_back(_framebufferRef);
  }

  _framebufferTransparentsRef =
      FramebufferManager::createFramebuffer(_N(LightingTransparents));
  {
    FramebufferManager::resetToDefault(_framebufferTransparentsRef);
    FramebufferManager::addResourceFlags(
        _framebufferTransparentsRef,
        Dod::Resources::ResourceFlags::kResourceVolatile);

    FramebufferManager::_descAttachedImages(_framebufferTransparentsRef)
        .push_back(_lightingBufferTransparentsImageRef);

    FramebufferManager::_descDimensions(_framebufferTransparentsRef) =
        glm::uvec2(RenderSystem::_backbufferDimensions.x,
                   RenderSystem::_backbufferDimensions.y);
    FramebufferManager::_descRenderPass(_framebufferTransparentsRef) =
        _renderPassRef;

    framebuffersToCreate.push_back(_framebufferTransparentsRef);
  }

  FramebufferManager::createResources(framebuffersToCreate);

  // Draw calls
  _drawCallRef = DrawCallManager::createDrawCall(_N(Lighting));
  {
    DrawCallManager::resetToDefault(_drawCallRef);
    DrawCallManager::addResourceFlags(
        _drawCallRef, Dod::Resources::ResourceFlags::kResourceVolatile);

    DrawCallManager::_descPipeline(_drawCallRef) = _pipelineRef;
    DrawCallManager::_descVertexCount(_drawCallRef) = 3u;

    DrawCallManager::bindBuffer(
        _drawCallRef, _N(PerInstance), GpuProgramType::kFragment,
        UniformManager::_perInstanceUniformBuffer,
        UboType::kPerInstanceFragment, sizeof(PerInstanceData));
    DrawCallManager::bindImage(
        _drawCallRef, _N(albedoTex), GpuProgramType::kFragment,
        ImageManager::getResourceByName(_N(GBufferAlbedo)),
        Samplers::kLinearClamp);
    DrawCallManager::bindImage(
        _drawCallRef, _N(normalTex), GpuProgramType::kFragment,
        ImageManager::getResourceByName(_N(GBufferNormal)),
        Samplers::kLinearClamp);
    DrawCallManager::bindImage(
        _drawCallRef, _N(parameter0Tex), GpuProgramType::kFragment,
        ImageManager::getResourceByName(_N(GBufferParameter0)),
        Samplers::kLinearClamp);
    DrawCallManager::bindImage(
        _drawCallRef, _N(depthTex), GpuProgramType::kFragment,
        ImageManager::getResourceByName(_N(GBufferDepth)),
        Samplers::kNearestClamp);
    DrawCallManager::bindImage(
        _drawCallRef, _N(ssaoTex), GpuProgramType::kFragment,
        ImageManager::getResourceByName(_N(SSAO)), Samplers::kLinearClamp);
    DrawCallManager::bindImage(_drawCallRef, _N(irradianceTex),
                               GpuProgramType::kFragment,
                               ImageManager::getResourceByName(
                                   _N(GCanyon_C_YumaPoint_3k_cube_irradiance)),
                               Samplers::kLinearClamp);
    DrawCallManager::bindImage(_drawCallRef, _N(specularTex),
                               GpuProgramType::kFragment,
                               ImageManager::getResourceByName(
                                   _N(GCanyon_C_YumaPoint_3k_cube_specular)),
                               Samplers::kLinearClamp);
    DrawCallManager::bindImage(
        _drawCallRef, _N(shadowBufferTex), GpuProgramType::kFragment,
        ImageManager::getResourceByName(_N(ShadowBuffer)), Samplers::kShadow);
    DrawCallManager::bindBuffer(
        _drawCallRef, _N(MaterialBuffer), GpuProgramType::kFragment,
        MaterialBuffer::_materialBuffer, UboType::kInvalidUbo,
        BufferManager::_descSizeInBytes(MaterialBuffer::_materialBuffer));
  }

  drawcallsToCreate.push_back(_drawCallRef);

  _drawCallTransparentsRef =
      DrawCallManager::createDrawCall(_N(LightingTransparents));
  {
    DrawCallManager::resetToDefault(_drawCallTransparentsRef);
    DrawCallManager::addResourceFlags(
        _drawCallTransparentsRef,
        Dod::Resources::ResourceFlags::kResourceVolatile);

    DrawCallManager::_descPipeline(_drawCallTransparentsRef) = _pipelineRef;
    DrawCallManager::_descVertexCount(_drawCallTransparentsRef) = 3u;

    DrawCallManager::bindBuffer(
        _drawCallTransparentsRef, _N(PerInstance), GpuProgramType::kFragment,
        UniformManager::_perInstanceUniformBuffer,
        UboType::kPerInstanceFragment, sizeof(PerInstanceData));
    DrawCallManager::bindImage(
        _drawCallTransparentsRef, _N(albedoTex), GpuProgramType::kFragment,
        ImageManager::getResourceByName(_N(GBufferTransparentsAlbedo)),
        Samplers::kLinearClamp);
    DrawCallManager::bindImage(
        _drawCallTransparentsRef, _N(normalTex), GpuProgramType::kFragment,
        ImageManager::getResourceByName(_N(GBufferTransparentsNormal)),
        Samplers::kLinearClamp);
    DrawCallManager::bindImage(
        _drawCallTransparentsRef, _N(parameter0Tex), GpuProgramType::kFragment,
        ImageManager::getResourceByName(_N(GBufferTransparentsParameter0)),
        Samplers::kLinearClamp);
    DrawCallManager::bindImage(
        _drawCallTransparentsRef, _N(depthTex), GpuProgramType::kFragment,
        ImageManager::getResourceByName(_N(GBufferTransparentsDepth)),
        Samplers::kNearestClamp);
    DrawCallManager::bindImage(
        _drawCallTransparentsRef, _N(ssaoTex), GpuProgramType::kFragment,
        ImageManager::getResourceByName(_N(SSAO)), Samplers::kLinearClamp);
    DrawCallManager::bindImage(_drawCallTransparentsRef, _N(irradianceTex),
                               GpuProgramType::kFragment,
                               ImageManager::getResourceByName(
                                   _N(GCanyon_C_YumaPoint_3k_cube_irradiance)),
                               Samplers::kLinearClamp);
    DrawCallManager::bindImage(_drawCallTransparentsRef, _N(specularTex),
                               GpuProgramType::kFragment,
                               ImageManager::getResourceByName(
                                   _N(GCanyon_C_YumaPoint_3k_cube_specular)),
                               Samplers::kLinearClamp);
    DrawCallManager::bindImage(
        _drawCallTransparentsRef, _N(shadowBufferTex),
        GpuProgramType::kFragment,
        ImageManager::getResourceByName(_N(ShadowBuffer)), Samplers::kShadow);
    DrawCallManager::bindBuffer(
        _drawCallTransparentsRef, _N(MaterialBuffer), GpuProgramType::kFragment,
        MaterialBuffer::_materialBuffer, UboType::kInvalidUbo,
        BufferManager::_descSizeInBytes(MaterialBuffer::_materialBuffer));
  }
  drawcallsToCreate.push_back(_drawCallTransparentsRef);

  DrawCallManager::createResources(drawcallsToCreate);
}

// <-

void Lighting::destroy() {}

// <-

void Lighting::render(float p_DeltaT, Components::CameraRef p_CameraRef)
{
  _INTR_PROFILE_CPU("Render Pass", "Render Lighting");
  _INTR_PROFILE_GPU("Render Lighting");

  renderLighting(_framebufferRef, _drawCallRef, _lightingBufferImageRef,
                 p_CameraRef);
  renderLighting(_framebufferTransparentsRef, _drawCallTransparentsRef,
                 _lightingBufferTransparentsImageRef, p_CameraRef);
}
}
}
}
}
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2011.  All rights reserved
 */
#include	"../../../StroikaPreComp.h"

#if		qHasFeature_libcurl
#include	<curl/curl.h>
#endif

#include	"../../../Characters/Format.h"
#include	"../../../Execution/Exceptions.h"

#include	"Client_libcurl.h"

using	namespace	Stroika::Foundation;
using	namespace	Stroika::Foundation::Characters;
using	namespace	Stroika::Foundation::IO;
using	namespace	Stroika::Foundation::IO::Network;
using	namespace	Stroika::Foundation::IO::Network::Transfer;

#if		qHasFeature_libcurl
namespace	{
	struct	ModuleInit_ {
		ModuleInit_ ()
		{
			curl_global_init (CURL_GLOBAL_ALL);
		}
	};
}
#endif

#if		qHasFeature_libcurl
namespace	{
	wstring	mkExceptMsg_ (LibCurlException::CURLcode ccode)
		{
			return String::FromUTF8 (curl_easy_strerror (static_cast<::CURLcode> (ccode))).As<wstring> ();
		}
}

/*
 ********************************************************************************
 ************************ Transfer::LibCurlException ****************************
 ********************************************************************************
 */
LibCurlException::LibCurlException (CURLcode ccode)
	: StringException (mkExceptMsg_ (ccode))
	, fCurlCode_ (ccode)
{
}

void	LibCurlException::DoThrowIfError (CURLcode status)
{
	if (status != 0) {
		Execution::DoThrow (LibCurlException (status));
	}
}
#endif

#if		qHasFeature_libcurl
/*
 ********************************************************************************
 ********************* Transfer::IConnection_LibCurl ****************************
 ********************************************************************************
 */
IConnection_LibCurl::IConnection_LibCurl ()
	: fCurlHandle_ (curl_easy_init ())
	, fCURLCache_URL_ ()
	, fResponseData_ ()
	, fSavedHeaders_ (nullptr)
{
}

IConnection_LibCurl::~IConnection_LibCurl ()
{
	if (fCurlHandle_ != nullptr) {
		curl_easy_cleanup (fCurlHandle_);
	}
	if (fSavedHeaders_ != nullptr) {
		curl_slist_free_all (fSavedHeaders_);
		fSavedHeaders_ = nullptr;
	}
}

URL		IConnection_LibCurl::GetURL () const override
{
	// needs work... - not sure this is safe - may need to cache orig... instead of reparsing...
	return URL (String::FromUTF8 (fCURLCache_URL_).As<wstring> ());
}

void	IConnection_LibCurl::SetURL (const URL& url) override
{
	MakeHandleIfNeeded_ ();
	fCURLCache_URL_ = String (url.GetURL ()).AsUTF8 ();
	LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_URL, fCURLCache_URL_.c_str ()));
}

void	IConnection_LibCurl::Close ()	override
{
	if (fCurlHandle_ != nullptr) {
		LibCurlException::DoThrowIfError (::curl_easy_cleanup (fCurlHandle_));
		fCurlHandle_ = nullptr;
	}
}

size_t	IConnection_LibCurl::ResponseWriteHandler_ (void* ptr, size_t size, size_t nmemb, void* userP)
{
	return reinterpret_cast<IConnection_LibCurl*> (userP)->ResponseWriteHandler_ (reinterpret_cast<const Byte*> (ptr), size * nmemb);
}

size_t	IConnection_LibCurl::ResponseWriteHandler_ (const Byte* ptr, size_t nBytes)
{
	fResponseData_.insert (ptr, ptr + nBytes);
	return nBytes;
}

size_t	IConnection_LibCurl::ResponseHeaderWriteHandler_ (void* ptr, size_t size, size_t nmemb, void* userP)
{
	return reinterpret_cast<IConnection_LibCurl*> (userP)->ResponseHeaderWriteHandler_ (reinterpret_cast<const Byte*> (ptr), size * nmemb);
}

size_t	IConnection_LibCurl::ResponseHeaderWriteHandler_ (const Byte* ptr, size_t nBytes)
{
	string tmp (reinterpret_cast<const char*> (ptr), nBytes);
	string::size_type i = tmp.find (':');
	String	from;
	String	to;
	if (i == string::npos) {
		from = String::FromUTF8 (tmp);
	}
	else {
		from = String::FromUTF8 (tmp.substr (0, i));
		to = String::FromUTF8 (tmp.substr (i+1));
	}
	from = from.Trim ();
	to = to.Trim ();
	fResponseHeaders_[from] = to;
	return nBytes;
}

Response	IConnection_LibCurl::SendAndRequest (const Request& request)	override
{
	MakeHandleIfNeeded_ ();
	fResponseData_.clear ();
	fResponseHeaders_.clear ();

	//grab useragent from request headers...
	//curl_easy_setopt (fCurlHandle_, CURLOPT_USERAGENT, "libcurl-agent/1.0");

	// grab initial headers and do POST/etc based on args in request...
	curl_slist*	tmpH	=	curl_slist_append (nullptr, "Expect: ");	//tmphack - really iterate over requst headers - with a few exceptions...
	LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_HTTPHEADER, tmpH));
	if (fSavedHeaders_ != nullptr) {
		curl_slist_free_all (fSavedHeaders_);
		fSavedHeaders_ = nullptr;
	}
	fSavedHeaders_ = tmpH;

	LibCurlException::DoThrowIfError (:: curl_easy_perform (fCurlHandle_));

	Response	response;
	response.fData = fResponseData_;

	long	resultCode	=	0;
	LibCurlException::DoThrowIfError (::curl_easy_getinfo (fCurlHandle_, CURLINFO_RESPONSE_CODE, &resultCode));
	response.fStatus = resultCode;
	response.fHeaders = fResponseHeaders_;
	response.fData = fResponseData_;
	return response;
}

void	IConnection_LibCurl::MakeHandleIfNeeded_ ()
{
	if (fCurlHandle_ == nullptr) {
		fCurlHandle_  = curl_easy_init ();
		LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_URL, fCURLCache_URL_.c_str ()));
	}
}
#endif

<commit_msg>more minor cleanups to Client_libcurl<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2011.  All rights reserved
 */
#include	"../../../StroikaPreComp.h"

#if		qHasFeature_libcurl
#include	<curl/curl.h>
#endif

#include	"../../../Characters/Format.h"
#include	"../../../Execution/Exceptions.h"

#include	"Client_libcurl.h"

using	namespace	Stroika::Foundation;
using	namespace	Stroika::Foundation::Characters;
using	namespace	Stroika::Foundation::IO;
using	namespace	Stroika::Foundation::IO::Network;
using	namespace	Stroika::Foundation::IO::Network::Transfer;

#if		qHasFeature_libcurl
namespace	{
	struct	ModuleInit_ {
		ModuleInit_ ()
		{
			curl_global_init (CURL_GLOBAL_ALL);
		}
	};
}
#endif

#if		qHasFeature_libcurl
namespace	{
	wstring	mkExceptMsg_ (LibCurlException::CURLcode ccode)
		{
			return String::FromUTF8 (curl_easy_strerror (static_cast<CURLcode> (ccode))).As<wstring> ();
		}
}

/*
 ********************************************************************************
 ************************ Transfer::LibCurlException ****************************
 ********************************************************************************
 */
LibCurlException::LibCurlException (CURLcode ccode)
	: StringException (mkExceptMsg_ (ccode))
	, fCurlCode_ (ccode)
{
}

void	LibCurlException::DoThrowIfError (CURLcode status)
{
	if (status != CURLE_OK) {
		Execution::DoThrow (LibCurlException (status));
	}
}
#endif

#if		qHasFeature_libcurl
/*
 ********************************************************************************
 ********************* Transfer::IConnection_LibCurl ****************************
 ********************************************************************************
 */
IConnection_LibCurl::IConnection_LibCurl ()
	: fCurlHandle_ (curl_easy_init ())
	, fCURLCache_URL_ ()
	, fResponseData_ ()
	, fSavedHeaders_ (nullptr)
{
}

IConnection_LibCurl::~IConnection_LibCurl ()
{
	if (fCurlHandle_ != nullptr) {
		curl_easy_cleanup (fCurlHandle_);
	}
	if (fSavedHeaders_ != nullptr) {
		curl_slist_free_all (fSavedHeaders_);
		fSavedHeaders_ = nullptr;
	}
}

URL		IConnection_LibCurl::GetURL () const override
{
	// needs work... - not sure this is safe - may need to cache orig... instead of reparsing...
	return URL (String::FromUTF8 (fCURLCache_URL_).As<wstring> ());
}

void	IConnection_LibCurl::SetURL (const URL& url) override
{
	MakeHandleIfNeeded_ ();
	fCURLCache_URL_ = String (url.GetURL ()).AsUTF8 ();
	LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_URL, fCURLCache_URL_.c_str ()));
}

void	IConnection_LibCurl::Close ()	override
{
	if (fCurlHandle_ != nullptr) {
		::curl_easy_cleanup (fCurlHandle_);
		fCurlHandle_ = nullptr;
	}
}

size_t	IConnection_LibCurl::ResponseWriteHandler_ (void* ptr, size_t size, size_t nmemb, void* userP)
{
	return reinterpret_cast<IConnection_LibCurl*> (userP)->ResponseWriteHandler_ (reinterpret_cast<const Byte*> (ptr), size * nmemb);
}

size_t	IConnection_LibCurl::ResponseWriteHandler_ (const Byte* ptr, size_t nBytes)
{
	fResponseData_.insert (fResponseData_.end (), ptr, ptr + nBytes);
	return nBytes;
}

size_t	IConnection_LibCurl::ResponseHeaderWriteHandler_ (void* ptr, size_t size, size_t nmemb, void* userP)
{
	return reinterpret_cast<IConnection_LibCurl*> (userP)->ResponseHeaderWriteHandler_ (reinterpret_cast<const Byte*> (ptr), size * nmemb);
}

size_t	IConnection_LibCurl::ResponseHeaderWriteHandler_ (const Byte* ptr, size_t nBytes)
{
	string tmp (reinterpret_cast<const char*> (ptr), nBytes);
	string::size_type i = tmp.find (':');
	String	from;
	String	to;
	if (i == string::npos) {
		from = String::FromUTF8 (tmp);
	}
	else {
		from = String::FromUTF8 (tmp.substr (0, i));
		to = String::FromUTF8 (tmp.substr (i+1));
	}
	from = from.Trim ();
	to = to.Trim ();
	fResponseHeaders_[from] = to;
	return nBytes;
}

Response	IConnection_LibCurl::SendAndRequest (const Request& request)	override
{
	MakeHandleIfNeeded_ ();
	fResponseData_.clear ();
	fResponseHeaders_.clear ();

	//grab useragent from request headers...
	//curl_easy_setopt (fCurlHandle_, CURLOPT_USERAGENT, "libcurl-agent/1.0");

	// grab initial headers and do POST/etc based on args in request...
	curl_slist*	tmpH	=	curl_slist_append (nullptr, "Expect: ");	//tmphack - really iterate over requst headers - with a few exceptions...
	LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_HTTPHEADER, tmpH));
	if (fSavedHeaders_ != nullptr) {
		curl_slist_free_all (fSavedHeaders_);
		fSavedHeaders_ = nullptr;
	}
	fSavedHeaders_ = tmpH;

	LibCurlException::DoThrowIfError (:: curl_easy_perform (fCurlHandle_));

	Response	response;
	response.fData = fResponseData_;

	long	resultCode	=	0;
	LibCurlException::DoThrowIfError (::curl_easy_getinfo (fCurlHandle_, CURLINFO_RESPONSE_CODE, &resultCode));
	response.fStatus = resultCode;
	response.fHeaders = fResponseHeaders_;
	response.fData = fResponseData_;
	return response;
}

void	IConnection_LibCurl::MakeHandleIfNeeded_ ()
{
	if (fCurlHandle_ == nullptr) {
		fCurlHandle_  = curl_easy_init ();
		LibCurlException::DoThrowIfError (::curl_easy_setopt (fCurlHandle_, CURLOPT_URL, fCURLCache_URL_.c_str ()));
	}
}
#endif

<|endoftext|>


<commit_before>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

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.
==============================================================================*/

// See docs in ../ops/math_ops.cc.

// This file uses MKL CBLAS xGEMM for acceleration of TF Matrix-Matrix
// Multiplication (MatMul) operations.
// We currently register this kernel only for MKL supported data
// types (float, double, complex64, complex128). The macro INTEL_MKL is defined
// by the build system only when MKL is chosen as an option at configure stage
// and when it is undefined at build time, this file becomes an empty
// compilation unit

#if defined(INTEL_MKL)

#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/register_types.h"
#include "tensorflow/core/kernels/fill_functor.h"

//This header file is part of MKL ML, need equivalent file in MKL DNN
#ifndef DO_NOT_USE_ML
#include "mkl_cblas.h"
#else
#include "mkldnn.h"
#endif

namespace tensorflow {

typedef Eigen::ThreadPoolDevice CPUDevice;

template <typename Device, typename T, bool USE_CUBLAS>
class MklMatMulOp : public OpKernel {
 public:
  explicit MklMatMulOp(OpKernelConstruction* ctx) : OpKernel(ctx) {
    OP_REQUIRES_OK(ctx, ctx->GetAttr("transpose_a", &transpose_a_));
    OP_REQUIRES_OK(ctx, ctx->GetAttr("transpose_b", &transpose_b_));
  }

  void Compute(OpKernelContext* ctx) override {
    const Tensor& a = ctx->input(0);
    const Tensor& b = ctx->input(1);

    // Check that the dimensions of the two matrices are valid.
    OP_REQUIRES(ctx, TensorShapeUtils::IsMatrix(a.shape()),
                errors::InvalidArgument("In[0] is not a matrix"));
    OP_REQUIRES(ctx, TensorShapeUtils::IsMatrix(b.shape()),
                errors::InvalidArgument("In[1] is not a matrix"));
    Eigen::array<Eigen::IndexPair<Eigen::DenseIndex>, 1> dim_pair;
    dim_pair[0].first = transpose_a_ ? 0 : 1;
    dim_pair[0].second = transpose_b_ ? 1 : 0;

    OP_REQUIRES(
        ctx, a.dim_size(dim_pair[0].first) == b.dim_size(dim_pair[0].second),
        errors::InvalidArgument(
            "Matrix size-incompatible: In[0]: ", a.shape().DebugString(),
            ", In[1]: ", b.shape().DebugString()));
    int a_dim_remaining = 1 - dim_pair[0].first;
    int b_dim_remaining = 1 - dim_pair[0].second;
    TensorShape out_shape(
        {a.dim_size(a_dim_remaining), b.dim_size(b_dim_remaining)});
    Tensor* out = nullptr;
    OP_REQUIRES_OK(ctx, ctx->allocate_output(0, out_shape, &out));

    if (out->NumElements() == 0) {
      // If a has shape [0, x] or b has shape [x, 0], the output shape
      // is a 0-element matrix, so there is nothing to do.
      return;
    }

    if (a.NumElements() == 0 || b.NumElements() == 0) {
      // If a has shape [x, 0] and b has shape [0, y], the
      // output shape is [x, y] where x and y are non-zero, so we fill
      // the output with zeros.
      functor::SetZeroFunctor<Device, T> f;
      f(ctx->eigen_device<Device>(), out->flat<T>());
      return;
    }

    const int m = a.dim_size(1 - dim_pair[0].first);
    const int k = a.dim_size(dim_pair[0].first);
    const int n = b.dim_size(1 - dim_pair[0].second);
    bool transpose_a = dim_pair[0].first == 0;
    bool transpose_b = dim_pair[0].second == 1;

    auto a_ptr = (a.template flat<T>().data());
    auto b_ptr = (b.template flat<T>().data());
    auto c_ptr = (out->template flat<T>().data());

    MklBlasGemm(transpose_a, transpose_b, m, n, k, a_ptr, transpose_a ? m : k,
                b_ptr, transpose_b ? k : n, c_ptr, n);
  }

 private:
  bool transpose_a_;
  bool transpose_b_;
  // --------------------------------------------------------------------------
  //
  // @brief Matrix-Matrix Multiplication with FP32 tensors, a, b, c using CBLAS
  // interface. c = op(a) * op(b)
  //
  // @param transa  Specifies the form of op(a) used in MatMul. If transa is
  // true, then op(a) = a^T, otherwise op(a) = a
  //
  // @param transb  Specifies the form of op(b) used in MatMul. If transb is
  // true, then op(b) = b^T, otherwise op(b) = b
  //
  // @param m       Specifies the number of rows of the matrix op(a) and of the
  // matrix c. The value of m must be at least zero.
  //
  // @param n       Specifies the number of columns of the matrix op(b) and the
  // number of columns of the matrix c. The value of n must be at least zero.
  //
  // @param k       Specifies the number of columns of the matrix op(a) and the
  // number of rows of the matrix op(b)
  //
  // @param a       Address of matrix a
  //
  // @param lda     Leading dimension of 'a' matrix. This is set at calling site
  // depending on transa parameter. Since TF uses row-major
  // layout, leading dimension is the stride between consecutive rows
  // lda = max(1,k) when transa is false, otherwise lda = max(1,m)
  //
  // @param b       Address of matrix b
  //
  // @param ldb     Leading dimension of 'b' matrix. This is set at calling site
  // depending on transb parameter. Since TF uses row-major
  // layout, leading dimension is the stride between consecutive rows
  // ldb = max(1,n) when transb is false, otherwise ldb = max(1,k)
  //
  // @param c       Address of matrix c
  //
  // @param ldc     Leading dimension of 'c' matrix. Since TF uses row-major
  // layout, leading dimension is the stride between consecutive rows, max(1,n)
  //
  // --------------------------------------------------------------------------
  void MklBlasGemm(bool transa, bool transb, const int m, const int n,
                   const int k, const float* a, const int lda, const float* b,
                   const int ldb, float* c, const int ldc) {
    // BLAS GEMM API defines Matrix Multiplication as c = alpha * op(a) * op(b)
    // + beta * c.
    // Since TF MatMul does not have parameters for alpha, beta, we set them to
    // 1.0 and 0.0 respectively.
    const float alpha = 1.0f;
    const float beta = 0.0f;
#if defined(DO_NOT_USE_ML)
    const char* const ftrans[]   = { "N", "T", "C"};
    int index_transa = transa? 1 : 0 ;
    int index_transb = transb? 1 : 0 ;
    VLOG(2) << "MKL DNN SGEMM called";
    //Using the fortran api of mkldnn
    //Since TF is in row major layout,reversing the order of A and B
    mkldnn_sgemm(ftrans[index_transb], ftrans[index_transa],
                &n, &m, &k, &alpha, b, &ldb, a, &lda, &beta, c, &ldc);
#else
    cblas_sgemm(CblasRowMajor, transa ? CblasTrans : CblasNoTrans,
                transb ? CblasTrans : CblasNoTrans, m, n, k, alpha, a, lda, b,
                ldb, beta, c, ldc);
#endif
  }

  // MKLDNN only supports SGEMM
#ifndef DO_NOT_USE_ML

  // Matrix-Matrix Multiplication with FP64 tensors. For detailed info about
  // parameters, look at FP32 function description.
  void MklBlasGemm(bool transa, bool transb, const int m, const int n,
                   const int k, const double* a, const int lda, const double* b,
                   const int ldb, double* c, const int ldc) {
    const double alpha = 1.0;
    const double beta = 0.0;
    cblas_dgemm(CblasRowMajor, transa ? CblasTrans : CblasNoTrans,
                transb ? CblasTrans : CblasNoTrans, m, n, k, alpha, a, lda, b,
                ldb, beta, c, ldc);
  }

  // Matrix-Matrix Multiplication with Complex64 (std::complex<float>) tensors.
  // For detailed info about parameters, look at FP32 function description.
  void MklBlasGemm(bool transa, bool transb, const int m, const int n,
                   const int k, const complex64* a, const int lda,
                   const complex64* b, const int ldb, complex64* c,
                   int const ldc) {
    const MKL_Complex8 alpha = {1.0f, 0.0f};
    const MKL_Complex8 beta = {0.0f, 0.0f};
    cblas_cgemm(CblasRowMajor, transa ? CblasTrans : CblasNoTrans,
                transb ? CblasTrans : CblasNoTrans, m, n, k, &alpha,
                reinterpret_cast<const MKL_Complex8*>(a), lda,
                reinterpret_cast<const MKL_Complex8*>(b), ldb, &beta,
                reinterpret_cast<MKL_Complex8*>(c), ldc);
  }

  // Matrix-Matrix Multiplication with Complex128 (std::complex<double>)
  // tensors. For detailed info about parameters, look at FP32 function
  // description.
  void MklBlasGemm(bool transa, bool transb, const int m, const int n,
                   const int k, const complex128* a, const int lda,
                   const complex128* b, const int ldb, complex128* c,
                   const int ldc) {
    const MKL_Complex16 alpha = {1.0, 0.0};
    const MKL_Complex16 beta = {0.0, 0.0};
    cblas_zgemm(CblasRowMajor, transa ? CblasTrans : CblasNoTrans,
                transb ? CblasTrans : CblasNoTrans, m, n, k, &alpha,
                reinterpret_cast<const MKL_Complex16*>(a), lda,
                reinterpret_cast<const MKL_Complex16*>(b), ldb, &beta,
                reinterpret_cast<MKL_Complex16*>(c), ldc);
  }
#endif
};

#define REGISTER_CPU(T)                                         \
  REGISTER_KERNEL_BUILDER(                                      \
      Name("MatMul").Device(DEVICE_CPU).TypeConstraint<T>("T"), \
      MklMatMulOp<CPUDevice, T, false /* cublas, ignored for CPU */>);

// TODO(inteltf) Consider template specialization when adding/removing
// additional types
TF_CALL_float(REGISTER_CPU);

#ifndef DO_NOT_USE_ML
TF_CALL_double(REGISTER_CPU);
TF_CALL_complex64(REGISTER_CPU);
TF_CALL_complex128(REGISTER_CPU);
#endif

}  // namespace tensorflow
#endif  // INTEL_MKL
<commit_msg>Removed unnecessary comment<commit_after>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

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.
==============================================================================*/

// See docs in ../ops/math_ops.cc.

// This file uses MKL CBLAS xGEMM for acceleration of TF Matrix-Matrix
// Multiplication (MatMul) operations.
// We currently register this kernel only for MKL supported data
// types (float, double, complex64, complex128). The macro INTEL_MKL is defined
// by the build system only when MKL is chosen as an option at configure stage
// and when it is undefined at build time, this file becomes an empty
// compilation unit

#if defined(INTEL_MKL)

#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/register_types.h"
#include "tensorflow/core/kernels/fill_functor.h"

#ifndef DO_NOT_USE_ML
#include "mkl_cblas.h"
#else
#include "mkldnn.h"
#endif

namespace tensorflow {

typedef Eigen::ThreadPoolDevice CPUDevice;

template <typename Device, typename T, bool USE_CUBLAS>
class MklMatMulOp : public OpKernel {
 public:
  explicit MklMatMulOp(OpKernelConstruction* ctx) : OpKernel(ctx) {
    OP_REQUIRES_OK(ctx, ctx->GetAttr("transpose_a", &transpose_a_));
    OP_REQUIRES_OK(ctx, ctx->GetAttr("transpose_b", &transpose_b_));
  }

  void Compute(OpKernelContext* ctx) override {
    const Tensor& a = ctx->input(0);
    const Tensor& b = ctx->input(1);

    // Check that the dimensions of the two matrices are valid.
    OP_REQUIRES(ctx, TensorShapeUtils::IsMatrix(a.shape()),
                errors::InvalidArgument("In[0] is not a matrix"));
    OP_REQUIRES(ctx, TensorShapeUtils::IsMatrix(b.shape()),
                errors::InvalidArgument("In[1] is not a matrix"));
    Eigen::array<Eigen::IndexPair<Eigen::DenseIndex>, 1> dim_pair;
    dim_pair[0].first = transpose_a_ ? 0 : 1;
    dim_pair[0].second = transpose_b_ ? 1 : 0;

    OP_REQUIRES(
        ctx, a.dim_size(dim_pair[0].first) == b.dim_size(dim_pair[0].second),
        errors::InvalidArgument(
            "Matrix size-incompatible: In[0]: ", a.shape().DebugString(),
            ", In[1]: ", b.shape().DebugString()));
    int a_dim_remaining = 1 - dim_pair[0].first;
    int b_dim_remaining = 1 - dim_pair[0].second;
    TensorShape out_shape(
        {a.dim_size(a_dim_remaining), b.dim_size(b_dim_remaining)});
    Tensor* out = nullptr;
    OP_REQUIRES_OK(ctx, ctx->allocate_output(0, out_shape, &out));

    if (out->NumElements() == 0) {
      // If a has shape [0, x] or b has shape [x, 0], the output shape
      // is a 0-element matrix, so there is nothing to do.
      return;
    }

    if (a.NumElements() == 0 || b.NumElements() == 0) {
      // If a has shape [x, 0] and b has shape [0, y], the
      // output shape is [x, y] where x and y are non-zero, so we fill
      // the output with zeros.
      functor::SetZeroFunctor<Device, T> f;
      f(ctx->eigen_device<Device>(), out->flat<T>());
      return;
    }

    const int m = a.dim_size(1 - dim_pair[0].first);
    const int k = a.dim_size(dim_pair[0].first);
    const int n = b.dim_size(1 - dim_pair[0].second);
    bool transpose_a = dim_pair[0].first == 0;
    bool transpose_b = dim_pair[0].second == 1;

    auto a_ptr = (a.template flat<T>().data());
    auto b_ptr = (b.template flat<T>().data());
    auto c_ptr = (out->template flat<T>().data());

    MklBlasGemm(transpose_a, transpose_b, m, n, k, a_ptr, transpose_a ? m : k,
                b_ptr, transpose_b ? k : n, c_ptr, n);
  }

 private:
  bool transpose_a_;
  bool transpose_b_;
  // --------------------------------------------------------------------------
  //
  // @brief Matrix-Matrix Multiplication with FP32 tensors, a, b, c using CBLAS
  // interface. c = op(a) * op(b)
  //
  // @param transa  Specifies the form of op(a) used in MatMul. If transa is
  // true, then op(a) = a^T, otherwise op(a) = a
  //
  // @param transb  Specifies the form of op(b) used in MatMul. If transb is
  // true, then op(b) = b^T, otherwise op(b) = b
  //
  // @param m       Specifies the number of rows of the matrix op(a) and of the
  // matrix c. The value of m must be at least zero.
  //
  // @param n       Specifies the number of columns of the matrix op(b) and the
  // number of columns of the matrix c. The value of n must be at least zero.
  //
  // @param k       Specifies the number of columns of the matrix op(a) and the
  // number of rows of the matrix op(b)
  //
  // @param a       Address of matrix a
  //
  // @param lda     Leading dimension of 'a' matrix. This is set at calling site
  // depending on transa parameter. Since TF uses row-major
  // layout, leading dimension is the stride between consecutive rows
  // lda = max(1,k) when transa is false, otherwise lda = max(1,m)
  //
  // @param b       Address of matrix b
  //
  // @param ldb     Leading dimension of 'b' matrix. This is set at calling site
  // depending on transb parameter. Since TF uses row-major
  // layout, leading dimension is the stride between consecutive rows
  // ldb = max(1,n) when transb is false, otherwise ldb = max(1,k)
  //
  // @param c       Address of matrix c
  //
  // @param ldc     Leading dimension of 'c' matrix. Since TF uses row-major
  // layout, leading dimension is the stride between consecutive rows, max(1,n)
  //
  // --------------------------------------------------------------------------
  void MklBlasGemm(bool transa, bool transb, const int m, const int n,
                   const int k, const float* a, const int lda, const float* b,
                   const int ldb, float* c, const int ldc) {
    // BLAS GEMM API defines Matrix Multiplication as c = alpha * op(a) * op(b)
    // + beta * c.
    // Since TF MatMul does not have parameters for alpha, beta, we set them to
    // 1.0 and 0.0 respectively.
    const float alpha = 1.0f;
    const float beta = 0.0f;
#if defined(DO_NOT_USE_ML)
    const char* const ftrans[]   = { "N", "T", "C"};
    int index_transa = transa? 1 : 0 ;
    int index_transb = transb? 1 : 0 ;
    VLOG(2) << "MKL DNN SGEMM called";
    //Using the fortran api of mkldnn
    //Since TF is in row major layout,reversing the order of A and B
    mkldnn_sgemm(ftrans[index_transb], ftrans[index_transa],
                &n, &m, &k, &alpha, b, &ldb, a, &lda, &beta, c, &ldc);
#else
    cblas_sgemm(CblasRowMajor, transa ? CblasTrans : CblasNoTrans,
                transb ? CblasTrans : CblasNoTrans, m, n, k, alpha, a, lda, b,
                ldb, beta, c, ldc);
#endif
  }

  // MKLDNN only supports SGEMM
#ifndef DO_NOT_USE_ML

  // Matrix-Matrix Multiplication with FP64 tensors. For detailed info about
  // parameters, look at FP32 function description.
  void MklBlasGemm(bool transa, bool transb, const int m, const int n,
                   const int k, const double* a, const int lda, const double* b,
                   const int ldb, double* c, const int ldc) {
    const double alpha = 1.0;
    const double beta = 0.0;
    cblas_dgemm(CblasRowMajor, transa ? CblasTrans : CblasNoTrans,
                transb ? CblasTrans : CblasNoTrans, m, n, k, alpha, a, lda, b,
                ldb, beta, c, ldc);
  }

  // Matrix-Matrix Multiplication with Complex64 (std::complex<float>) tensors.
  // For detailed info about parameters, look at FP32 function description.
  void MklBlasGemm(bool transa, bool transb, const int m, const int n,
                   const int k, const complex64* a, const int lda,
                   const complex64* b, const int ldb, complex64* c,
                   int const ldc) {
    const MKL_Complex8 alpha = {1.0f, 0.0f};
    const MKL_Complex8 beta = {0.0f, 0.0f};
    cblas_cgemm(CblasRowMajor, transa ? CblasTrans : CblasNoTrans,
                transb ? CblasTrans : CblasNoTrans, m, n, k, &alpha,
                reinterpret_cast<const MKL_Complex8*>(a), lda,
                reinterpret_cast<const MKL_Complex8*>(b), ldb, &beta,
                reinterpret_cast<MKL_Complex8*>(c), ldc);
  }

  // Matrix-Matrix Multiplication with Complex128 (std::complex<double>)
  // tensors. For detailed info about parameters, look at FP32 function
  // description.
  void MklBlasGemm(bool transa, bool transb, const int m, const int n,
                   const int k, const complex128* a, const int lda,
                   const complex128* b, const int ldb, complex128* c,
                   const int ldc) {
    const MKL_Complex16 alpha = {1.0, 0.0};
    const MKL_Complex16 beta = {0.0, 0.0};
    cblas_zgemm(CblasRowMajor, transa ? CblasTrans : CblasNoTrans,
                transb ? CblasTrans : CblasNoTrans, m, n, k, &alpha,
                reinterpret_cast<const MKL_Complex16*>(a), lda,
                reinterpret_cast<const MKL_Complex16*>(b), ldb, &beta,
                reinterpret_cast<MKL_Complex16*>(c), ldc);
  }
#endif
};

#define REGISTER_CPU(T)                                         \
  REGISTER_KERNEL_BUILDER(                                      \
      Name("MatMul").Device(DEVICE_CPU).TypeConstraint<T>("T"), \
      MklMatMulOp<CPUDevice, T, false /* cublas, ignored for CPU */>);

// TODO(inteltf) Consider template specialization when adding/removing
// additional types
TF_CALL_float(REGISTER_CPU);

#ifndef DO_NOT_USE_ML
TF_CALL_double(REGISTER_CPU);
TF_CALL_complex64(REGISTER_CPU);
TF_CALL_complex128(REGISTER_CPU);
#endif

}  // namespace tensorflow
#endif  // INTEL_MKL
<|endoftext|>


<commit_before>/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/register_types.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/framework/tensor_util.h"
#include "tensorflow/core/framework/types.h"
#include "tensorflow/core/util/sparse/sparse_tensor.h"

namespace tensorflow {

template <typename T, typename Treal>
class SparseAddOp : public OpKernel {
 public:
  explicit SparseAddOp(OpKernelConstruction *ctx) : OpKernel(ctx) {}

  void Compute(OpKernelContext *ctx) override {
    // (0) validations
    const Tensor *a_indices, *b_indices, *a_values_t, *b_values_t, *a_shape,
        *b_shape, *thresh_t;

    OP_REQUIRES_OK(ctx, ctx->input("a_indices", &a_indices));
    OP_REQUIRES_OK(ctx, ctx->input("b_indices", &b_indices));
    OP_REQUIRES(ctx,
                TensorShapeUtils::IsMatrix(a_indices->shape()) &&
                    TensorShapeUtils::IsMatrix(b_indices->shape()),
                errors::InvalidArgument(
                    "Input indices should be matrices but received shapes: ",
                    a_indices->shape().DebugString(), " and ",
                    b_indices->shape().DebugString()));
    const int64 a_nnz = a_indices->dim_size(0);
    const int64 b_nnz = b_indices->dim_size(0);

    OP_REQUIRES_OK(ctx, ctx->input("a_values", &a_values_t));
    OP_REQUIRES_OK(ctx, ctx->input("b_values", &b_values_t));

    OP_REQUIRES(ctx,
                TensorShapeUtils::IsVector(a_values_t->shape()) &&
                    TensorShapeUtils::IsVector(b_values_t->shape()),
                errors::InvalidArgument(
                    "Input values should be vectors but received shapes: ",
                    a_values_t->shape().DebugString(), " and ",
                    b_values_t->shape().DebugString()));
    auto a_values = ctx->input(1).vec<T>();
    auto b_values = ctx->input(4).vec<T>();
    OP_REQUIRES(
        ctx, a_values.size() == a_nnz && b_values.size() == b_nnz,
        errors::InvalidArgument("Expected ", a_nnz, " and ", b_nnz,
                                " non-empty input values, got ",
                                a_values.size(), " and ", b_values.size()));

    OP_REQUIRES_OK(ctx, ctx->input("a_shape", &a_shape));
    OP_REQUIRES_OK(ctx, ctx->input("b_shape", &b_shape));
    OP_REQUIRES(ctx,
                TensorShapeUtils::IsVector(a_shape->shape()) &&
                    TensorShapeUtils::IsVector(b_shape->shape()),
                errors::InvalidArgument(
                    "Input shapes should be a vector but received shapes ",
                    a_shape->shape().DebugString(), " and ",
                    b_shape->shape().DebugString()));
    OP_REQUIRES(
        ctx, a_shape->IsSameSize(*b_shape),
        errors::InvalidArgument(
            "Operands do not have the same ranks; got shapes: ",
            a_shape->SummarizeValue(10), " and ", b_shape->SummarizeValue(10)));
    const auto a_shape_flat = a_shape->flat<int64>();
    const auto b_shape_flat = b_shape->flat<int64>();
    for (int i = 0; i < a_shape->NumElements(); ++i) {
      OP_REQUIRES(ctx, a_shape_flat(i) == b_shape_flat(i),
                  errors::InvalidArgument(
                      "Operands' shapes do not match: got ", a_shape_flat(i),
                      " and ", b_shape_flat(i), " for dimension ", i));
    }

    OP_REQUIRES_OK(ctx, ctx->input("thresh", &thresh_t));
    OP_REQUIRES(ctx, TensorShapeUtils::IsScalar(thresh_t->shape()),
                errors::InvalidArgument(
                    "The magnitude threshold must be a scalar: got shape ",
                    thresh_t->shape().DebugString()));
    // std::abs() so that it works for complex{64,128} values as well
    const Treal thresh = thresh_t->scalar<Treal>()();

    // (1) do a pass over inputs, and append values and indices to vectors
    auto a_indices_mat = a_indices->matrix<int64>();
    auto b_indices_mat = b_indices->matrix<int64>();
    std::vector<std::pair<bool, int64>> entries_to_copy;  // from_a?, idx
    entries_to_copy.reserve(a_nnz + b_nnz);
    std::vector<T> out_values;
    const int num_dims = a_shape->dim_size(0);

    // The input and output sparse tensors are assumed to be ordered along
    // increasing dimension number.
    int64 i = 0, j = 0;
    T s;
    while (i < a_nnz && j < b_nnz) {
      switch (sparse::DimComparator::cmp(a_indices_mat, b_indices_mat, i, j,
                                         num_dims)) {
        case -1:
          entries_to_copy.emplace_back(true, i);
          out_values.push_back(a_values(i));
          ++i;
          break;
        case 0:
          s = a_values(i) + b_values(j);
          if (thresh <= std::abs(s)) {
            entries_to_copy.emplace_back(true, i);
            out_values.push_back(s);
          }
          ++i;
          ++j;
          break;
        case 1:
          entries_to_copy.emplace_back(false, j);
          out_values.push_back(b_values(j));
          ++j;
          break;
      }
    }

#define HANDLE_LEFTOVERS(A_OR_B, IDX, IS_A)     \
  while (IDX < A_OR_B##_nnz) {                  \
    entries_to_copy.emplace_back(IS_A, IDX);    \
    out_values.push_back(A_OR_B##_values(IDX)); \
    ++IDX;                                      \
  }

    // at most one of these calls appends new values
    HANDLE_LEFTOVERS(a, i, true);
    HANDLE_LEFTOVERS(b, j, false);
#undef HANDLE_LEFTOVERS

    // (2) allocate and fill output tensors
    const int64 sum_nnz = out_values.size();
    Tensor *out_indices_t, *out_values_t;
    OP_REQUIRES_OK(ctx,
                   ctx->allocate_output(0, TensorShape({sum_nnz, num_dims}),
                                        &out_indices_t));
    OP_REQUIRES_OK(
        ctx, ctx->allocate_output(1, TensorShape({sum_nnz}), &out_values_t));
    auto out_indices_mat = out_indices_t->matrix<int64>();
    auto out_values_flat = out_values_t->vec<T>();

    for (i = 0; i < sum_nnz; ++i) {
      const bool from_a = entries_to_copy[i].first;
      const int64 idx = entries_to_copy[i].second;
      out_indices_mat.chip<0>(i) =
          from_a ? a_indices_mat.chip<0>(idx) : b_indices_mat.chip<0>(idx);
    }
    std::copy_n(out_values.begin(), sum_nnz, &out_values_flat(0));
    ctx->set_output(2, *a_shape);
  }
};

#define REGISTER_KERNELS(type, thresh_type)                           \
  REGISTER_KERNEL_BUILDER(                                            \
      Name("SparseAdd").Device(DEVICE_CPU).TypeConstraint<type>("T"), \
      SparseAddOp<type, thresh_type>)

// The list below is equivalent to TF_CALL_REAL_NUMBER_TYPES, minus uint8.  This
// is because std::abs() on uint8 does not compile.
REGISTER_KERNELS(float, float);
REGISTER_KERNELS(double, double);
REGISTER_KERNELS(int64, int64);
REGISTER_KERNELS(int32, int32);
REGISTER_KERNELS(int16, int16);
REGISTER_KERNELS(int8, int8);
REGISTER_KERNELS(complex64, float);
REGISTER_KERNELS(complex128, double);
#undef REGISTER_KERNELS
}  // namespace tensorflow
<commit_msg>Fixing nondeterministic nullptr access.<commit_after>/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/register_types.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/framework/tensor_util.h"
#include "tensorflow/core/framework/types.h"
#include "tensorflow/core/util/sparse/sparse_tensor.h"

namespace tensorflow {

template <typename T, typename Treal>
class SparseAddOp : public OpKernel {
 public:
  explicit SparseAddOp(OpKernelConstruction *ctx) : OpKernel(ctx) {}

  void Compute(OpKernelContext *ctx) override {
    // (0) validations
    const Tensor *a_indices, *b_indices, *a_values_t, *b_values_t, *a_shape,
        *b_shape, *thresh_t;

    OP_REQUIRES_OK(ctx, ctx->input("a_indices", &a_indices));
    OP_REQUIRES_OK(ctx, ctx->input("b_indices", &b_indices));
    OP_REQUIRES(ctx,
                TensorShapeUtils::IsMatrix(a_indices->shape()) &&
                    TensorShapeUtils::IsMatrix(b_indices->shape()),
                errors::InvalidArgument(
                    "Input indices should be matrices but received shapes: ",
                    a_indices->shape().DebugString(), " and ",
                    b_indices->shape().DebugString()));
    const int64 a_nnz = a_indices->dim_size(0);
    const int64 b_nnz = b_indices->dim_size(0);

    OP_REQUIRES_OK(ctx, ctx->input("a_values", &a_values_t));
    OP_REQUIRES_OK(ctx, ctx->input("b_values", &b_values_t));

    OP_REQUIRES(ctx,
                TensorShapeUtils::IsVector(a_values_t->shape()) &&
                    TensorShapeUtils::IsVector(b_values_t->shape()),
                errors::InvalidArgument(
                    "Input values should be vectors but received shapes: ",
                    a_values_t->shape().DebugString(), " and ",
                    b_values_t->shape().DebugString()));
    auto a_values = ctx->input(1).vec<T>();
    auto b_values = ctx->input(4).vec<T>();
    OP_REQUIRES(
        ctx, a_values.size() == a_nnz && b_values.size() == b_nnz,
        errors::InvalidArgument("Expected ", a_nnz, " and ", b_nnz,
                                " non-empty input values, got ",
                                a_values.size(), " and ", b_values.size()));

    OP_REQUIRES_OK(ctx, ctx->input("a_shape", &a_shape));
    OP_REQUIRES_OK(ctx, ctx->input("b_shape", &b_shape));
    OP_REQUIRES(ctx,
                TensorShapeUtils::IsVector(a_shape->shape()) &&
                    TensorShapeUtils::IsVector(b_shape->shape()),
                errors::InvalidArgument(
                    "Input shapes should be a vector but received shapes ",
                    a_shape->shape().DebugString(), " and ",
                    b_shape->shape().DebugString()));
    OP_REQUIRES(
        ctx, a_shape->IsSameSize(*b_shape),
        errors::InvalidArgument(
            "Operands do not have the same ranks; got shapes: ",
            a_shape->SummarizeValue(10), " and ", b_shape->SummarizeValue(10)));
    const auto a_shape_flat = a_shape->flat<int64>();
    const auto b_shape_flat = b_shape->flat<int64>();
    for (int i = 0; i < a_shape->NumElements(); ++i) {
      OP_REQUIRES(ctx, a_shape_flat(i) == b_shape_flat(i),
                  errors::InvalidArgument(
                      "Operands' shapes do not match: got ", a_shape_flat(i),
                      " and ", b_shape_flat(i), " for dimension ", i));
    }

    OP_REQUIRES_OK(ctx, ctx->input("thresh", &thresh_t));
    OP_REQUIRES(ctx, TensorShapeUtils::IsScalar(thresh_t->shape()),
                errors::InvalidArgument(
                    "The magnitude threshold must be a scalar: got shape ",
                    thresh_t->shape().DebugString()));
    // std::abs() so that it works for complex{64,128} values as well
    const Treal thresh = thresh_t->scalar<Treal>()();

    // (1) do a pass over inputs, and append values and indices to vectors
    auto a_indices_mat = a_indices->matrix<int64>();
    auto b_indices_mat = b_indices->matrix<int64>();
    std::vector<std::pair<bool, int64>> entries_to_copy;  // from_a?, idx
    entries_to_copy.reserve(a_nnz + b_nnz);
    std::vector<T> out_values;
    const int num_dims = a_shape->dim_size(0);

    // The input and output sparse tensors are assumed to be ordered along
    // increasing dimension number.
    int64 i = 0, j = 0;
    T s;
    while (i < a_nnz && j < b_nnz) {
      switch (sparse::DimComparator::cmp(a_indices_mat, b_indices_mat, i, j,
                                         num_dims)) {
        case -1:
          entries_to_copy.emplace_back(true, i);
          out_values.push_back(a_values(i));
          ++i;
          break;
        case 0:
          s = a_values(i) + b_values(j);
          if (thresh <= std::abs(s)) {
            entries_to_copy.emplace_back(true, i);
            out_values.push_back(s);
          }
          ++i;
          ++j;
          break;
        case 1:
          entries_to_copy.emplace_back(false, j);
          out_values.push_back(b_values(j));
          ++j;
          break;
      }
    }

#define HANDLE_LEFTOVERS(A_OR_B, IDX, IS_A)     \
  while (IDX < A_OR_B##_nnz) {                  \
    entries_to_copy.emplace_back(IS_A, IDX);    \
    out_values.push_back(A_OR_B##_values(IDX)); \
    ++IDX;                                      \
  }

    // at most one of these calls appends new values
    HANDLE_LEFTOVERS(a, i, true);
    HANDLE_LEFTOVERS(b, j, false);
#undef HANDLE_LEFTOVERS

    // (2) allocate and fill output tensors
    const int64 sum_nnz = out_values.size();
    Tensor *out_indices_t, *out_values_t;
    OP_REQUIRES_OK(ctx,
                   ctx->allocate_output(0, TensorShape({sum_nnz, num_dims}),
                                        &out_indices_t));
    OP_REQUIRES_OK(
        ctx, ctx->allocate_output(1, TensorShape({sum_nnz}), &out_values_t));
    auto out_indices_mat = out_indices_t->matrix<int64>();
    auto out_values_flat = out_values_t->vec<T>();

    for (i = 0; i < sum_nnz; ++i) {
      const bool from_a = entries_to_copy[i].first;
      const int64 idx = entries_to_copy[i].second;
      out_indices_mat.chip<0>(i) =
          from_a ? a_indices_mat.chip<0>(idx) : b_indices_mat.chip<0>(idx);
    }
    if (sum_nnz > 0) {
      std::copy_n(out_values.begin(), sum_nnz, &out_values_flat(0));
    }
    ctx->set_output(2, *a_shape);
  }
};

#define REGISTER_KERNELS(type, thresh_type)                           \
  REGISTER_KERNEL_BUILDER(                                            \
      Name("SparseAdd").Device(DEVICE_CPU).TypeConstraint<type>("T"), \
      SparseAddOp<type, thresh_type>)

// The list below is equivalent to TF_CALL_REAL_NUMBER_TYPES, minus uint8.  This
// is because std::abs() on uint8 does not compile.
REGISTER_KERNELS(float, float);
REGISTER_KERNELS(double, double);
REGISTER_KERNELS(int64, int64);
REGISTER_KERNELS(int32, int32);
REGISTER_KERNELS(int16, int16);
REGISTER_KERNELS(int8, int8);
REGISTER_KERNELS(complex64, float);
REGISTER_KERNELS(complex128, double);
#undef REGISTER_KERNELS
}  // namespace tensorflow
<|endoftext|>


<commit_before>// Copyright by Contributors
#include <xgboost/objective.h>

#include "../helpers.h"

TEST(Objective, LinearRegressionGPair) {
  xgboost::ObjFunction * obj = xgboost::ObjFunction::Create("reg:linear");
  std::vector<std::pair<std::string, std::string> > args;
  obj->Configure(args);
  CheckObjFunction(obj,
                   {0, 0.1, 0.9,   1,    0,  0.1, 0.9,  1},
                   {0,   0,   0,   0,    1,    1,    1, 1},
                   {1,   1,   1,   1,    1,    1,    1, 1},
                   {0, 0.1, 0.9, 1.0, -1.0, -0.9, -0.1, 0},
                   {1,   1,   1,   1,    1,    1,    1, 1});

  ASSERT_NO_THROW(obj->DefaultEvalMetric());
}

TEST(Objective, LogisticRegressionGPair) {
  xgboost::ObjFunction * obj = xgboost::ObjFunction::Create("reg:logistic");
  std::vector<std::pair<std::string, std::string> > args;
  obj->Configure(args);
  CheckObjFunction(obj,
                   {   0,  0.1,  0.9,    1,    0,   0.1,  0.9,      1},
                   {   0,    0,    0,    0,    1,     1,     1,     1},
                   {   1,    1,    1,    1,    1,     1,     1,     1},
                   { 0.5, 0.52, 0.71, 0.73, -0.5, -0.47, -0.28, -0.26},
                   {0.25, 0.24, 0.20, 0.19, 0.25,  0.24,  0.20,  0.19});
}

TEST(Objective, LogisticRegressionBasic) {
  xgboost::ObjFunction * obj = xgboost::ObjFunction::Create("reg:logistic");
  std::vector<std::pair<std::string, std::string> > args;
  obj->Configure(args);

  // test label validation
  EXPECT_ANY_THROW(CheckObjFunction(obj, {0}, {10}, {1}, {0}, {0}))
    << "Expected error when label not in range [0,1] for LogisticRegression";

  // test ProbToMargin
  EXPECT_NEAR(obj->ProbToMargin(0.1), -2.197, 0.01);
  EXPECT_NEAR(obj->ProbToMargin(0.5), 0, 0.01);
  EXPECT_NEAR(obj->ProbToMargin(0.9), 2.197, 0.01);
  EXPECT_ANY_THROW(obj->ProbToMargin(10))
    << "Expected error when base_score not in range [0,1] for LogisticRegression";

  // test PredTransform
  std::vector<xgboost::bst_float> preds = {0, 0.1, 0.5, 0.9, 1};
  std::vector<xgboost::bst_float> out_preds = {0.5, 0.524, 0.622, 0.710, 0.731};
  obj->PredTransform(&preds);
  for (int i = 0; i < preds.size(); ++i) {
    EXPECT_NEAR(preds[i], out_preds[i], 0.01);
  }
}

TEST(Objective, LogisticRawGPair) {
  xgboost::ObjFunction * obj = xgboost::ObjFunction::Create("binary:logitraw");
  std::vector<std::pair<std::string, std::string> > args;
  obj->Configure(args);
  CheckObjFunction(obj,
                   {   0,  0.1,  0.9,    1,    0,   0.1,   0.9,     1},
                   {   0,    0,    0,    0,    1,     1,     1,     1},
                   {   1,    1,    1,    1,    1,     1,     1,     1},
                   { 0.5, 0.52, 0.71, 0.73, -0.5, -0.47, -0.28, -0.26},
                   {0.25, 0.24, 0.20, 0.19, 0.25,  0.24,  0.20,  0.19});
}

TEST(Objective, PoissonRegressionGPair) {
  xgboost::ObjFunction * obj = xgboost::ObjFunction::Create("count:poisson");
  std::vector<std::pair<std::string, std::string> > args;
  args.push_back(std::make_pair("max_delta_step", "0.1"));
  obj->Configure(args);
  CheckObjFunction(obj,
                   {   0,  0.1,  0.9,    1,    0,  0.1,  0.9,    1},
                   {   0,    0,    0,    0,    1,    1,    1,    1},
                   {   1,    1,    1,    1,    1,    1,    1,    1},
                   {   1, 1.10, 2.45, 2.71,    0, 0.10, 1.45, 1.71},
                   {1.10, 1.22, 2.71, 3.00, 1.10, 1.22, 2.71, 3.00});
}

TEST(Objective, PoissonRegressionBasic) {
  xgboost::ObjFunction * obj = xgboost::ObjFunction::Create("count:poisson");
  std::vector<std::pair<std::string, std::string> > args;
  obj->Configure(args);

  // test label validation
  EXPECT_ANY_THROW(CheckObjFunction(obj, {0}, {-1}, {1}, {0}, {0}))
    << "Expected error when label < 0 for PoissonRegression";

  // test ProbToMargin
  EXPECT_NEAR(obj->ProbToMargin(0.1), -2.30, 0.01);
  EXPECT_NEAR(obj->ProbToMargin(0.5), -0.69, 0.01);
  EXPECT_NEAR(obj->ProbToMargin(0.9), -0.10, 0.01);

  // test PredTransform
  std::vector<xgboost::bst_float> preds = {0, 0.1, 0.5, 0.9, 1};
  std::vector<xgboost::bst_float> out_preds = {1, 1.10, 1.64, 2.45, 2.71};
  obj->PredTransform(&preds);
  for (int i = 0; i < preds.size(); ++i) {
    EXPECT_NEAR(preds[i], out_preds[i], 0.01);
  }
}
<commit_msg>tests/cpp: Add tests for GammaRegression<commit_after>// Copyright by Contributors
#include <xgboost/objective.h>

#include "../helpers.h"

TEST(Objective, LinearRegressionGPair) {
  xgboost::ObjFunction * obj = xgboost::ObjFunction::Create("reg:linear");
  std::vector<std::pair<std::string, std::string> > args;
  obj->Configure(args);
  CheckObjFunction(obj,
                   {0, 0.1, 0.9,   1,    0,  0.1, 0.9,  1},
                   {0,   0,   0,   0,    1,    1,    1, 1},
                   {1,   1,   1,   1,    1,    1,    1, 1},
                   {0, 0.1, 0.9, 1.0, -1.0, -0.9, -0.1, 0},
                   {1,   1,   1,   1,    1,    1,    1, 1});

  ASSERT_NO_THROW(obj->DefaultEvalMetric());
}

TEST(Objective, LogisticRegressionGPair) {
  xgboost::ObjFunction * obj = xgboost::ObjFunction::Create("reg:logistic");
  std::vector<std::pair<std::string, std::string> > args;
  obj->Configure(args);
  CheckObjFunction(obj,
                   {   0,  0.1,  0.9,    1,    0,   0.1,  0.9,      1},
                   {   0,    0,    0,    0,    1,     1,     1,     1},
                   {   1,    1,    1,    1,    1,     1,     1,     1},
                   { 0.5, 0.52, 0.71, 0.73, -0.5, -0.47, -0.28, -0.26},
                   {0.25, 0.24, 0.20, 0.19, 0.25,  0.24,  0.20,  0.19});
}

TEST(Objective, LogisticRegressionBasic) {
  xgboost::ObjFunction * obj = xgboost::ObjFunction::Create("reg:logistic");
  std::vector<std::pair<std::string, std::string> > args;
  obj->Configure(args);

  // test label validation
  EXPECT_ANY_THROW(CheckObjFunction(obj, {0}, {10}, {1}, {0}, {0}))
    << "Expected error when label not in range [0,1] for LogisticRegression";

  // test ProbToMargin
  EXPECT_NEAR(obj->ProbToMargin(0.1), -2.197, 0.01);
  EXPECT_NEAR(obj->ProbToMargin(0.5), 0, 0.01);
  EXPECT_NEAR(obj->ProbToMargin(0.9), 2.197, 0.01);
  EXPECT_ANY_THROW(obj->ProbToMargin(10))
    << "Expected error when base_score not in range [0,1] for LogisticRegression";

  // test PredTransform
  std::vector<xgboost::bst_float> preds = {0, 0.1, 0.5, 0.9, 1};
  std::vector<xgboost::bst_float> out_preds = {0.5, 0.524, 0.622, 0.710, 0.731};
  obj->PredTransform(&preds);
  for (int i = 0; i < preds.size(); ++i) {
    EXPECT_NEAR(preds[i], out_preds[i], 0.01);
  }
}

TEST(Objective, LogisticRawGPair) {
  xgboost::ObjFunction * obj = xgboost::ObjFunction::Create("binary:logitraw");
  std::vector<std::pair<std::string, std::string> > args;
  obj->Configure(args);
  CheckObjFunction(obj,
                   {   0,  0.1,  0.9,    1,    0,   0.1,   0.9,     1},
                   {   0,    0,    0,    0,    1,     1,     1,     1},
                   {   1,    1,    1,    1,    1,     1,     1,     1},
                   { 0.5, 0.52, 0.71, 0.73, -0.5, -0.47, -0.28, -0.26},
                   {0.25, 0.24, 0.20, 0.19, 0.25,  0.24,  0.20,  0.19});
}

TEST(Objective, PoissonRegressionGPair) {
  xgboost::ObjFunction * obj = xgboost::ObjFunction::Create("count:poisson");
  std::vector<std::pair<std::string, std::string> > args;
  args.push_back(std::make_pair("max_delta_step", "0.1"));
  obj->Configure(args);
  CheckObjFunction(obj,
                   {   0,  0.1,  0.9,    1,    0,  0.1,  0.9,    1},
                   {   0,    0,    0,    0,    1,    1,    1,    1},
                   {   1,    1,    1,    1,    1,    1,    1,    1},
                   {   1, 1.10, 2.45, 2.71,    0, 0.10, 1.45, 1.71},
                   {1.10, 1.22, 2.71, 3.00, 1.10, 1.22, 2.71, 3.00});
}

TEST(Objective, PoissonRegressionBasic) {
  xgboost::ObjFunction * obj = xgboost::ObjFunction::Create("count:poisson");
  std::vector<std::pair<std::string, std::string> > args;
  obj->Configure(args);

  // test label validation
  EXPECT_ANY_THROW(CheckObjFunction(obj, {0}, {-1}, {1}, {0}, {0}))
    << "Expected error when label < 0 for PoissonRegression";

  // test ProbToMargin
  EXPECT_NEAR(obj->ProbToMargin(0.1), -2.30, 0.01);
  EXPECT_NEAR(obj->ProbToMargin(0.5), -0.69, 0.01);
  EXPECT_NEAR(obj->ProbToMargin(0.9), -0.10, 0.01);

  // test PredTransform
  std::vector<xgboost::bst_float> preds = {0, 0.1, 0.5, 0.9, 1};
  std::vector<xgboost::bst_float> out_preds = {1, 1.10, 1.64, 2.45, 2.71};
  obj->PredTransform(&preds);
  for (int i = 0; i < preds.size(); ++i) {
    EXPECT_NEAR(preds[i], out_preds[i], 0.01);
  }
}

TEST(Objective, GammaRegressionGPair) {
  xgboost::ObjFunction * obj = xgboost::ObjFunction::Create("reg:gamma");
  std::vector<std::pair<std::string, std::string> > args;
  obj->Configure(args);
  CheckObjFunction(obj,
                   {0, 0.1, 0.9, 1, 0,  0.1,  0.9,    1},
                   {0,   0,   0, 0, 1,    1,    1,    1},
                   {1,   1,   1, 1, 1,    1,    1,    1},
                   {1,   1,   1, 1, 0, 0.09, 0.59, 0.63},
                   {0,   0,   0, 0, 1, 0.90, 0.40, 0.36});
}

TEST(Objective, GammaRegressionBasic) {
  xgboost::ObjFunction * obj = xgboost::ObjFunction::Create("reg:gamma");
  std::vector<std::pair<std::string, std::string> > args;
  obj->Configure(args);

  // test label validation
  EXPECT_ANY_THROW(CheckObjFunction(obj, {0}, {-1}, {1}, {0}, {0}))
    << "Expected error when label < 0 for GammaRegression";

  // test ProbToMargin
  EXPECT_NEAR(obj->ProbToMargin(0.1), -2.30, 0.01);
  EXPECT_NEAR(obj->ProbToMargin(0.5), -0.69, 0.01);
  EXPECT_NEAR(obj->ProbToMargin(0.9), -0.10, 0.01);

  // test PredTransform
  std::vector<xgboost::bst_float> preds = {0, 0.1, 0.5, 0.9, 1};
  std::vector<xgboost::bst_float> out_preds = {1, 1.10, 1.64, 2.45, 2.71};
  obj->PredTransform(&preds);
  for (int i = 0; i < preds.size(); ++i) {
    EXPECT_NEAR(preds[i], out_preds[i], 0.01);
  }
}
<|endoftext|>