<commit_before>// Copyright 2020 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include "iree_tf_compiler/TF/Passes.h"
#include "mlir-hlo/Dialect/mhlo/IR/chlo_ops.h"
#include "mlir-hlo/Dialect/mhlo/IR/hlo_ops.h"
#include "mlir-hlo/Dialect/mhlo/transforms/rewriters.h"
#include "mlir/Dialect/Linalg/IR/LinalgOps.h"
#include "mlir/Dialect/MemRef/IR/MemRef.h"
#include "mlir/Dialect/Shape/IR/Shape.h"
#include "mlir/Dialect/StandardOps/IR/Ops.h"
#include "mlir/Dialect/Tensor/IR/Tensor.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Support/LLVM.h"
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_device.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_executor.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_ops.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_saved_model.h"
#include "tensorflow/compiler/mlir/tensorflow/transforms/lower_tf.h"
#include "tensorflow/compiler/mlir/xla/transforms/passes.h"

namespace mlir {
namespace iree_integrations {
namespace TF {

// This is a customized version of the TF to XLA lowering in:
//    tensorflow/compiler/mlir/xla/transforms/legalize_tf.cc
// It does not require the same number of options as we can hardcode as the pass
// the IREE requires.
class ConvertToMHLOPass : public PassWrapper<ConvertToMHLOPass, FunctionPass> {
  void getDependentDialects(DialectRegistry &registry) const override {
    registry.insert<mlir::linalg::LinalgDialect, mlir::TF::TensorFlowDialect,
                    mlir::tf_executor::TensorFlowExecutorDialect,
                    mlir::tf_device::TensorFlowDeviceDialect,
                    mlir::tf_saved_model::TensorFlowSavedModelDialect,
                    chlo::HloClientDialect, mhlo::MhloDialect,
                    shape::ShapeDialect, StandardOpsDialect>();
  }

 public:
  ConvertToMHLOPass() = default;
  ConvertToMHLOPass(const ConvertToMHLOPass &) {}

  void runOnFunction() override {
    auto op = getFunction();
    MLIRContext *context = op.getContext();

    // Lower TF Patterns must be separate from canonocalization patterns as
    // they are sometimes inversions of eachother.
    OwningRewritePatternList lowerTfPatterns(&getContext());
    mlir::TF::PopulateLoweringTFPatterns(context, &lowerTfPatterns);

    OwningRewritePatternList canonicalizePatterns(&getContext());
    for (auto *op : context->getRegisteredOperations()) {
      op->getCanonicalizationPatterns(canonicalizePatterns, context);
    }

    OwningRewritePatternList patterns(&getContext());
    // Note that the `OperationConverter` orders patterns lexicographically by:
    // 1) Ascending legalization depth (i.e., minimum number of patterns
    // necessary to arrive at conversion target).
    // 2) Descending pattern benefit.
    // 3) Order of patterns in `OwningRewritePatternList`.

    // Add TF->HLO legalization patterns.
    mhlo::PopulateLegalizeTfPatterns(context, &patterns);

    // TF::PopulateLoweringTFPatterns(context, &patterns);

    // ConstantLike op is convenient to create splat constants, but is
    // canonicalized to plain HLO constant if statically shaped. Add the
    // canonicalization pattern to pattern list to enable multi-hop lowering.
    chlo::ConstantLikeOp::getCanonicalizationPatterns(patterns, context);

    ConversionTarget target(*context);
    target.addLegalDialect<chlo::HloClientDialect>();
    target.addLegalDialect<mhlo::MhloDialect>();
    target.addLegalDialect<mlir::StandardOpsDialect>();
    target.addLegalDialect<shape::ShapeDialect>();
    target.addLegalDialect<tensor::TensorDialect>();
    target.addLegalOp<mlir::CallOp>();
    target.addLegalOp<mlir::tensor::CastOp>();
    target.addLegalOp<mlir::memref::DimOp>();

    // TODO(suderman): Enable logicistic op for lowering once the op is
    // supported in IREE. Also, remove the numerically unstable ConvertSigmoidOp
    // pattern in the legalize-tf pass.
    target.addIllegalOp<mhlo::LogisticOp>();

    DenseSet<Operation *> prevUnconvertedOps;
    DenseSet<Operation *> unconvertedOps;

    FrozenRewritePatternSet frozenPatterns(std::move(patterns));
    FrozenRewritePatternSet frozenCanonicalizePatterns(
        std::move(canonicalizePatterns));
    FrozenRewritePatternSet frozenTfPatterns(std::move(lowerTfPatterns));
    while (true) {
      if (failed(
              applyPatternsAndFoldGreedily(op, frozenCanonicalizePatterns))) {
        return signalPassFailure();
      }

      if (failed(applyPatternsAndFoldGreedily(op, frozenTfPatterns))) {
        return signalPassFailure();
      }

      if (failed(applyPartialConversion(op, target, frozenPatterns,
                                        &unconvertedOps))) {
        return signalPassFailure();
      }

      if (prevUnconvertedOps == unconvertedOps) break;
      prevUnconvertedOps = std::move(unconvertedOps);
    }
  }

 private:
  Option<bool> allow_partial_conversion_{
      *this, "allow-partial-conversion",
      llvm::cl::desc("Allow operations that can't be legalized."),
      llvm::cl::init(false)};
  Option<bool> legalize_chlo_{
      *this, "legalize-chlo",
      llvm::cl::desc(
          "Also legalizes intermediate chlo ops to hlo (default true)"),
      llvm::cl::init(false)};
  Option<bool> use_tf2xla_fallback_{
      *this, "use-tf2xla-fallback",
      llvm::cl::desc(
          "Also use TF2XLA fallback for legalization (default false)"),
      llvm::cl::init(false)};
  Option<std::string> device_type_{
      *this, "device-type",
      llvm::cl::desc(
          "The device type used by TF2XLA fallback. Must be specified if "
          "use-tf2xla-fallback is true, otherwise not used."),
      llvm::cl::init("INVALID_DEVICE_TYPE")};
};

std::unique_ptr<FunctionPass> createConvertToMHLOPass() {
  return std::make_unique<ConvertToMHLOPass>();
}

static PassRegistration<ConvertToMHLOPass> pass(
    "iree-tf-convert-to-mhlo",
    "Converts from TensorFlow to the XLA MHLO dialect");

}  // namespace TF
}  // namespace iree_integrations
}  // namespace mlir
<commit_msg>Switch Softmax and LogSoftmax ops to be expansions instead of TF->HLO legalizations.<commit_after>// Copyright 2020 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include "iree_tf_compiler/TF/Passes.h"
#include "mlir-hlo/Dialect/mhlo/IR/chlo_ops.h"
#include "mlir-hlo/Dialect/mhlo/IR/hlo_ops.h"
#include "mlir-hlo/Dialect/mhlo/transforms/rewriters.h"
#include "mlir/Dialect/Linalg/IR/LinalgOps.h"
#include "mlir/Dialect/MemRef/IR/MemRef.h"
#include "mlir/Dialect/Shape/IR/Shape.h"
#include "mlir/Dialect/StandardOps/IR/Ops.h"
#include "mlir/Dialect/Tensor/IR/Tensor.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Support/LLVM.h"
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_device.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_executor.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_ops.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_saved_model.h"
#include "tensorflow/compiler/mlir/tensorflow/transforms/lower_tf.h"
#include "tensorflow/compiler/mlir/xla/transforms/passes.h"

namespace mlir {
namespace iree_integrations {
namespace TF {

// This is a customized version of the TF to XLA lowering in:
//    tensorflow/compiler/mlir/xla/transforms/legalize_tf.cc
// It does not require the same number of options as we can hardcode as the pass
// the IREE requires.
class ConvertToMHLOPass : public PassWrapper<ConvertToMHLOPass, FunctionPass> {
  void getDependentDialects(DialectRegistry &registry) const override {
    registry.insert<mlir::linalg::LinalgDialect, mlir::TF::TensorFlowDialect,
                    mlir::tf_executor::TensorFlowExecutorDialect,
                    mlir::tf_device::TensorFlowDeviceDialect,
                    mlir::tf_saved_model::TensorFlowSavedModelDialect,
                    chlo::HloClientDialect, mhlo::MhloDialect,
                    shape::ShapeDialect, StandardOpsDialect>();
  }

 public:
  ConvertToMHLOPass() = default;
  ConvertToMHLOPass(const ConvertToMHLOPass &) {}

  void runOnFunction() override {
    auto op = getFunction();
    MLIRContext *context = op.getContext();

    // Lower TF Patterns must be separate from canonocalization patterns as
    // they are sometimes inversions of eachother.
    OwningRewritePatternList lowerTfPatterns(&getContext());
    mlir::TF::PopulateTFLoweringBeforeHLOPatterns(context, &lowerTfPatterns);

    OwningRewritePatternList canonicalizePatterns(&getContext());
    for (auto *op : context->getRegisteredOperations()) {
      op->getCanonicalizationPatterns(canonicalizePatterns, context);
    }

    OwningRewritePatternList patterns(&getContext());
    // Note that the `OperationConverter` orders patterns lexicographically by:
    // 1) Ascending legalization depth (i.e., minimum number of patterns
    // necessary to arrive at conversion target).
    // 2) Descending pattern benefit.
    // 3) Order of patterns in `OwningRewritePatternList`.

    // Add TF->HLO legalization patterns.
    mhlo::PopulateLegalizeTfPatterns(context, &patterns);

    // TF::PopulateLoweringTFPatterns(context, &patterns);

    // ConstantLike op is convenient to create splat constants, but is
    // canonicalized to plain HLO constant if statically shaped. Add the
    // canonicalization pattern to pattern list to enable multi-hop lowering.
    chlo::ConstantLikeOp::getCanonicalizationPatterns(patterns, context);

    ConversionTarget target(*context);
    target.addLegalDialect<chlo::HloClientDialect>();
    target.addLegalDialect<mhlo::MhloDialect>();
    target.addLegalDialect<mlir::StandardOpsDialect>();
    target.addLegalDialect<shape::ShapeDialect>();
    target.addLegalDialect<tensor::TensorDialect>();
    target.addLegalOp<mlir::CallOp>();
    target.addLegalOp<mlir::tensor::CastOp>();
    target.addLegalOp<mlir::memref::DimOp>();

    // TODO(suderman): Enable logicistic op for lowering once the op is
    // supported in IREE. Also, remove the numerically unstable ConvertSigmoidOp
    // pattern in the legalize-tf pass.
    target.addIllegalOp<mhlo::LogisticOp>();

    DenseSet<Operation *> prevUnconvertedOps;
    DenseSet<Operation *> unconvertedOps;

    FrozenRewritePatternSet frozenPatterns(std::move(patterns));
    FrozenRewritePatternSet frozenCanonicalizePatterns(
        std::move(canonicalizePatterns));
    FrozenRewritePatternSet frozenTfPatterns(std::move(lowerTfPatterns));
    while (true) {
      if (failed(
              applyPatternsAndFoldGreedily(op, frozenCanonicalizePatterns))) {
        return signalPassFailure();
      }

      if (failed(applyPatternsAndFoldGreedily(op, frozenTfPatterns))) {
        return signalPassFailure();
      }

      if (failed(applyPartialConversion(op, target, frozenPatterns,
                                        &unconvertedOps))) {
        return signalPassFailure();
      }

      if (prevUnconvertedOps == unconvertedOps) break;
      prevUnconvertedOps = std::move(unconvertedOps);
    }
  }

 private:
  Option<bool> allow_partial_conversion_{
      *this, "allow-partial-conversion",
      llvm::cl::desc("Allow operations that can't be legalized."),
      llvm::cl::init(false)};
  Option<bool> legalize_chlo_{
      *this, "legalize-chlo",
      llvm::cl::desc(
          "Also legalizes intermediate chlo ops to hlo (default true)"),
      llvm::cl::init(false)};
  Option<bool> use_tf2xla_fallback_{
      *this, "use-tf2xla-fallback",
      llvm::cl::desc(
          "Also use TF2XLA fallback for legalization (default false)"),
      llvm::cl::init(false)};
  Option<std::string> device_type_{
      *this, "device-type",
      llvm::cl::desc(
          "The device type used by TF2XLA fallback. Must be specified if "
          "use-tf2xla-fallback is true, otherwise not used."),
      llvm::cl::init("INVALID_DEVICE_TYPE")};
};

std::unique_ptr<FunctionPass> createConvertToMHLOPass() {
  return std::make_unique<ConvertToMHLOPass>();
}

static PassRegistration<ConvertToMHLOPass> pass(
    "iree-tf-convert-to-mhlo",
    "Converts from TensorFlow to the XLA MHLO dialect");

}  // namespace TF
}  // namespace iree_integrations
}  // namespace mlir
<|endoftext|>


<commit_before>/* =======================================================================
   Copyright (c) 2011, Institute for Microelectronics, TU Wien
   http://www.iue.tuwien.ac.at
                             -----------------
           ViennaFVM - The Vienna Finite Volume Method Library
                             -----------------

   authors:    Karl Rupp                          rupp@iue.tuwien.ac.at
               (add your name here)

   license:    To be discussed, see file LICENSE in the ViennaFVM base directory
======================================================================= */

//#define VIENNAFVM_DEBUG

// Define NDEBUG to get any reasonable performance with ublas:
#define NDEBUG

#define VIENNAMINI_DEBUG

// include necessary system headers
#include <iostream>

// ViennaMini main include:
#include "viennamini/simulator.hpp"

// Vienna Includes
#include "viennamaterials/library.hpp"
#include "viennamaterials/kernels/pugixml.hpp"

/** @brief Structure the device by assigning 'roles', such as 'Oxide' to a segment.
    Also, assign a doping to the semiconductor regions */
template<typename Domain, typename Segmentation, typename Storage>
void prepare(viennamini::device<Domain, Segmentation, Storage>& device)
{
  const int source          = 0;
  const int channel         = 1;
  const int drain           = 2;
  const int oxide           = 3;
  const int gate_contact    = 4;
  const int body            = 5;
  const int body_contact    = 6;
  const int source_contact  = 7;
  const int drain_contact   = 8;

  // Segment 0: Source
  device.assign_name          (source, "source");
  device.assign_material      (source, "Si");
  device.assign_semiconductor (source, 1.E24, 1.E8);   // ND, NA

  // Segment 1: Channel
  device.assign_name          (channel, "channel");
  device.assign_material      (channel, "Si");
  device.assign_semiconductor (channel, 1.E17, 1.E15);

  // Segment 2: Drain
  device.assign_name          (drain, "drain");
  device.assign_material      (drain, "Si");
  device.assign_semiconductor (drain, 1.E24, 1.E8);

  // Segment 3: Oxide
  device.assign_name          (oxide, "oxide");
  device.assign_material      (oxide, "HfO2");
  device.assign_oxide         (oxide);

  // Segment 4: Gate Contact
  device.assign_name          (gate_contact, "gate_contact");
  device.assign_material      (gate_contact, "Cu");
  device.assign_contact       (gate_contact);

  // Segment 5: Body
  device.assign_name          (body, "body");
  device.assign_material      (body, "Si");
  device.assign_semiconductor (body, 1.E17, 1.E15);

  // Segment 6: Body Contact
  device.assign_name          (body_contact, "body_contact");
  device.assign_material      (body_contact, "Cu");
  device.assign_contact       (body_contact);

  // Segment 7: Source Contact
  device.assign_name          (source_contact, "source_contact");
  device.assign_material      (source_contact, "Cu");
  device.assign_contact       (source_contact);

  // Segment 8: Drain Contact
  device.assign_name          (drain_contact, "drain_contact");
  device.assign_material      (drain_contact, "Cu");
  device.assign_contact       (drain_contact);

}

/** @brief Assign actual values to the dirichlet contacts */
void prepare_boundary_conditions(viennamini::config& config)
{
  const int gate_contact    = 4;
  const int body_contact    = 6;
  const int source_contact  = 7;
  const int drain_contact   = 8;

  // Segment 4: Gate Contact
  config.assign_contact(gate_contact, 0.3, 0.0);  // segment id, contact potential, workfunction

  // Segment 6: Body Contact
  config.assign_contact(body_contact, 0.0, 0.0);

  // Segment 7: Source Contact
  config.assign_contact(source_contact, 0.0, 0.0);

  // Segment 8: Drain Contact
  config.assign_contact(drain_contact, 0.3, 0.0);
}

/** @brief Scales the entire simulation domain (device) by the provided factor. This is accomplished by multiplying all point coordinates with this factor. */
template <typename DomainType>
void scale_domain(DomainType & domain, double factor)
{
  typedef typename viennagrid::result_of::element<DomainType, viennagrid::vertex_tag>::type         VertexType;
  typedef typename viennagrid::result_of::element_range<DomainType, viennagrid::vertex_tag>::type   VertexContainer;
  typedef typename viennagrid::result_of::iterator<VertexContainer>::type                           VertexIterator;

  VertexContainer vertices = viennagrid::elements<VertexType>(domain);
  for ( VertexIterator vit = vertices.begin();
        vit != vertices.end();
        ++vit )
  {
    viennagrid::point(domain, *vit) *= factor;
  }
}

int main()
{
    typedef double                                                       numeric_type;
    typedef viennagrid::domain_t< viennagrid::config::triangular_2d >    domain_type;
    typedef viennagrid::result_of::segmentation<domain_type>::type       segmentation_type;
    typedef segmentation_type::segment_type                              segment_type;
    typedef viennadata::storage<>                                        storage_type;

    //
    // Create a domain from file
    //
    domain_type         domain;
    segmentation_type   segments(domain);
    storage_type        storage;

    try
    {
    viennagrid::io::netgen_reader my_reader;
    my_reader(domain, segments, "../examples/data/half-trigate-2.mesh");
    }
    catch (...)
    {
    std::cerr << "File-Reader failed. Aborting program..." << std::endl;
    return EXIT_FAILURE;
    }

    //
    // scale to nanometer
    //
    scale_domain(domain, 1e-9);

    //
    // Prepare material library
    //
    typedef vmat::Library<vmat::tag::pugixml>::type  material_library_type;
    material_library_type matlib;
    matlib.load("../external/ViennaMaterials/database/materials.xml");

    //
    // Create a device and a config object
    //
    typedef viennamini::device<domain_type, segmentation_type, storage_type>   device_type;
    device_type device(domain, segments, storage);
    viennamini::config config;

    //
    // Prepare device, i.e., assign doping and segment roles,
    // e.g., oxide, semiconductor, contact
    //
    prepare(device);

    //
    // Assign contact values
    //
    prepare_boundary_conditions(config);

    //
    // Set simulation parameters
    //
    config.temperature()                        = 300;
    config.damping()                            = 0.3;
    config.linear_breaktol()                    = 1.0E-13;
    config.linear_iterations()                  = 500;
    config.nonlinear_iterations()               = 100;
    config.nonlinear_breaktol()                 = 1.0E-3;
    config.initial_guess_smoothing_iterations() = 6;

    //
    // Create a simulator object
    //
    typedef viennamini::simulator<device_type, material_library_type>     simulator_type;
    simulator_type simulator(device, matlib, config);

    //
    // Run the simulation
    //
    simulator();

    // Write results to vtk files
    simulator.write_result("trigate");

    std::cout << "********************************************" << std::endl;
    std::cout << "* MOSFET simulation finished successfully! *" << std::endl;
    std::cout << "********************************************" << std::endl;
    return EXIT_SUCCESS;
}

<commit_msg>fixed trigate example: the test domain type was wrong (still doesn't converge)<commit_after>/* =======================================================================
   Copyright (c) 2011, Institute for Microelectronics, TU Wien
   http://www.iue.tuwien.ac.at
                             -----------------
           ViennaFVM - The Vienna Finite Volume Method Library
                             -----------------

   authors:    Karl Rupp                          rupp@iue.tuwien.ac.at
               (add your name here)

   license:    To be discussed, see file LICENSE in the ViennaFVM base directory
======================================================================= */

//#define VIENNAFVM_DEBUG

// Define NDEBUG to get any reasonable performance with ublas:
#define NDEBUG

#define VIENNAMINI_DEBUG

// include necessary system headers
#include <iostream>

// ViennaMini main include:
#include "viennamini/simulator.hpp"

// Vienna Includes
#include "viennamaterials/library.hpp"
#include "viennamaterials/kernels/pugixml.hpp"

#include "viennagrid/io/vtk_writer.hpp"

/** @brief Structure the device by assigning 'roles', such as 'Oxide' to a segment.
    Also, assign a doping to the semiconductor regions */
template<typename Domain, typename Segmentation, typename Storage>
void prepare(viennamini::device<Domain, Segmentation, Storage>& device)
{
  const int source          = 0;
  const int channel         = 1;
  const int drain           = 2;
  const int oxide           = 3;
  const int gate_contact    = 4;
  const int body            = 5;
  const int body_contact    = 6;
  const int source_contact  = 7;
  const int drain_contact   = 8;

  // Segment 0: Source
  device.assign_name          (source, "source");
  device.assign_material      (source, "Si");
  device.assign_semiconductor (source, 1.E24, 1.E8);   // ND, NA

  // Segment 1: Channel
  device.assign_name          (channel, "channel");
  device.assign_material      (channel, "Si");
  device.assign_semiconductor (channel, 1.E17, 1.E15);

  // Segment 2: Drain
  device.assign_name          (drain, "drain");
  device.assign_material      (drain, "Si");
  device.assign_semiconductor (drain, 1.E24, 1.E8);

  // Segment 3: Oxide
  device.assign_name          (oxide, "oxide");
  device.assign_material      (oxide, "HfO2");
  device.assign_oxide         (oxide);

  // Segment 4: Gate Contact
  device.assign_name          (gate_contact, "gate_contact");
  device.assign_material      (gate_contact, "Cu");
  device.assign_contact       (gate_contact);

  // Segment 5: Body
  device.assign_name          (body, "body");
  device.assign_material      (body, "Si");
  device.assign_semiconductor (body, 1.E17, 1.E15);

  // Segment 6: Body Contact
  device.assign_name          (body_contact, "body_contact");
  device.assign_material      (body_contact, "Cu");
  device.assign_contact       (body_contact);

  // Segment 7: Source Contact
  device.assign_name          (source_contact, "source_contact");
  device.assign_material      (source_contact, "Cu");
  device.assign_contact       (source_contact);

  // Segment 8: Drain Contact
  device.assign_name          (drain_contact, "drain_contact");
  device.assign_material      (drain_contact, "Cu");
  device.assign_contact       (drain_contact);

}

/** @brief Assign actual values to the dirichlet contacts */
void prepare_boundary_conditions(viennamini::config& config)
{
  const int gate_contact    = 4;
  const int body_contact    = 6;
  const int source_contact  = 7;
  const int drain_contact   = 8;

  // Segment 4: Gate Contact
  config.assign_contact(gate_contact, 0.3, 0.0);  // segment id, contact potential, workfunction

  // Segment 6: Body Contact
  config.assign_contact(body_contact, 0.0, 0.0);

  // Segment 7: Source Contact
  config.assign_contact(source_contact, 0.0, 0.0);

  // Segment 8: Drain Contact
  config.assign_contact(drain_contact, 0.3, 0.0);
}

/** @brief Scales the entire simulation domain (device) by the provided factor. This is accomplished by multiplying all point coordinates with this factor. */
template <typename DomainType>
void scale_domain(DomainType & domain, double factor)
{
  typedef typename viennagrid::result_of::element<DomainType, viennagrid::vertex_tag>::type         VertexType;
  typedef typename viennagrid::result_of::element_range<DomainType, viennagrid::vertex_tag>::type   VertexContainer;
  typedef typename viennagrid::result_of::iterator<VertexContainer>::type                           VertexIterator;

  VertexContainer vertices = viennagrid::elements<VertexType>(domain);
  for ( VertexIterator vit = vertices.begin();
        vit != vertices.end();
        ++vit )
  {
    viennagrid::point(domain, *vit) *= factor;
  }
}

int main(int argc, char* argv[])
{
    typedef double                                                       numeric_type;
    typedef viennagrid::domain_t< viennagrid::config::tetrahedral_3d >    domain_type;
    typedef viennagrid::result_of::segmentation<domain_type>::type       segmentation_type;
    typedef segmentation_type::segment_type                              segment_type;
    typedef viennadata::storage<>                                        storage_type;

    //
    // Create a domain from file
    //
    domain_type         domain;
    segmentation_type   segments(domain);
    storage_type        storage;

    try
    {
    viennagrid::io::netgen_reader my_reader;
    my_reader(domain, segments, "../examples/data/half-trigate-2.mesh");
    }
    catch (...)
    {
    std::cerr << "File-Reader failed. Aborting program..." << std::endl;
    return EXIT_FAILURE;
    }

    //
    // scale to nanometer
    //
    scale_domain(domain, 1e-9);

    //
    // Prepare material library
    //
    typedef vmat::Library<vmat::tag::pugixml>::type  material_library_type;
    material_library_type matlib;
    matlib.load("../external/ViennaMaterials/database/materials.xml");

    //
    // Create a device and a config object
    //
    typedef viennamini::device<domain_type, segmentation_type, storage_type>   device_type;
    device_type device(domain, segments, storage);
    viennamini::config config;

    //
    // Prepare device, i.e., assign doping and segment roles,
    // e.g., oxide, semiconductor, contact
    //
    prepare(device);

    //
    // Assign contact values
    //
    prepare_boundary_conditions(config);

    //
    // Set simulation parameters
    //
    config.temperature()                        = 300;
    config.damping()                            = 0.3;
    config.linear_breaktol()                    = 1.0E-13;
    config.linear_iterations()                  = 500;
    config.nonlinear_iterations()               = 100;
    config.nonlinear_breaktol()                 = 1.0E-3;
    config.initial_guess_smoothing_iterations() = 6;

    //
    // Create a simulator object
    //
    typedef viennamini::simulator<device_type, material_library_type>     simulator_type;
    simulator_type simulator(device, matlib, config);

    //
    // Run the simulation
    //
    simulator();

    // Write results to vtk files
    simulator.write_result("trigate");

    std::cout << "********************************************" << std::endl;
    std::cout << "* MOSFET simulation finished successfully! *" << std::endl;
    std::cout << "********************************************" << std::endl;
    return EXIT_SUCCESS;
}

<|endoftext|>


<commit_before>/*
 *  Copyright 2019-2022 Diligent Graphics LLC
 *  Copyright 2015-2019 Egor Yusov
 *
 *  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.
 *
 *  In no event and under no legal theory, whether in tort (including negligence),
 *  contract, or otherwise, unless required by applicable law (such as deliberate
 *  and grossly negligent acts) or agreed to in writing, shall any Contributor be
 *  liable for any damages, including any direct, indirect, special, incidental,
 *  or consequential damages of any character arising as a result of this License or
 *  out of the use or inability to use the software (including but not limited to damages
 *  for loss of goodwill, work stoppage, computer failure or malfunction, or any and
 *  all other commercial damages or losses), even if such Contributor has been advised
 *  of the possibility of such damages.
 */

#include "pch.h"

#include "QueryManagerD3D12.hpp"

#include <algorithm>

#include "D3D12TypeConversions.hpp"
#include "GraphicsAccessories.hpp"
#include "CommandContext.hpp"
#include "Align.hpp"
#include "RenderDeviceD3D12Impl.hpp"

namespace Diligent
{

static Uint32 GetQueryDataSize(QUERY_TYPE QueryType)
{
    // clang-format off
    switch (QueryType)
    {
        case QUERY_TYPE_OCCLUSION:
        case QUERY_TYPE_BINARY_OCCLUSION:
        case QUERY_TYPE_TIMESTAMP:
        case QUERY_TYPE_DURATION:
            return sizeof(Uint64);
            break;

        case QUERY_TYPE_PIPELINE_STATISTICS:
            return sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS);
            break;

        static_assert(QUERY_TYPE_NUM_TYPES == 6, "Not all QUERY_TYPE enum values are tested");

        default:
            UNEXPECTED("Unexpected query type");
            return 0;
    }
    // clang-format on
}

void QueryManagerD3D12::QueryHeapInfo::Init(ID3D12Device*                pd3d12Device,
                                            const D3D12_QUERY_HEAP_DESC& d3d12HeapDesc,
                                            QUERY_TYPE                   QueryType,
                                            Uint32&                      CurrResolveBufferOffset)
{
    VERIFY_EXPR(!m_pd3d12QueryHeap);

    m_Type       = QueryType;
    m_QueryCount = d3d12HeapDesc.Count;

    auto hr = pd3d12Device->CreateQueryHeap(&d3d12HeapDesc, __uuidof(m_pd3d12QueryHeap), reinterpret_cast<void**>(&m_pd3d12QueryHeap));
    CHECK_D3D_RESULT_THROW(hr, "Failed to create D3D12 query heap");

    // AlignedDestinationBufferOffset must be a multiple of 8 bytes.
    // https://microsoft.github.io/DirectX-Specs/d3d/CountersAndQueries.html#resolvequerydata
    m_AlignedQueryDataSize    = AlignUp(GetQueryDataSize(QueryType), Uint32{8});
    m_ResolveBufferBaseOffset = CurrResolveBufferOffset;
    CurrResolveBufferOffset += m_AlignedQueryDataSize * m_QueryCount;

    m_AvailableQueries.resize(m_QueryCount);
    for (Uint32 i = 0; i < m_QueryCount; ++i)
        m_AvailableQueries[i] = i;
}

Uint32 QueryManagerD3D12::QueryHeapInfo::Allocate()
{
    Uint32 Index = InvalidIndex;

    std::lock_guard<std::mutex> Lock{m_AvailableQueriesMtx};
    if (!m_AvailableQueries.empty())
    {
        Index = m_AvailableQueries.back();
        m_AvailableQueries.pop_back();
        m_MaxAllocatedQueries = std::max(m_MaxAllocatedQueries, m_QueryCount - static_cast<Uint32>(m_AvailableQueries.size()));
    }

    return Index;
}

void QueryManagerD3D12::QueryHeapInfo::Release(Uint32 Index)
{
    VERIFY(Index < m_QueryCount, "Query index ", Index, " is out of range");

    std::lock_guard<std::mutex> Lock{m_AvailableQueriesMtx};
    VERIFY(std::find(m_AvailableQueries.begin(), m_AvailableQueries.end(), Index) == m_AvailableQueries.end(),
           "Index ", Index, " already present in available queries list");
    m_AvailableQueries.push_back(Index);
}

QueryManagerD3D12::QueryHeapInfo::~QueryHeapInfo()
{
    if (m_AvailableQueries.size() != m_QueryCount)
    {
        auto OutstandingQueries = m_QueryCount - m_AvailableQueries.size();
        if (OutstandingQueries == 1)
        {
            LOG_ERROR_MESSAGE("One query of type ", GetQueryTypeString(m_Type),
                              " has not been returned to the query manager");
        }
        else
        {
            LOG_ERROR_MESSAGE(OutstandingQueries, " queries of type ", GetQueryTypeString(m_Type),
                              " have not been returned to the query manager");
        }
    }
}

QueryManagerD3D12::QueryManagerD3D12(RenderDeviceD3D12Impl* pDeviceD3D12Impl,
                                     const Uint32           QueryHeapSizes[],
                                     SoftwareQueueIndex     CommandQueueId,
                                     HardwareQueueIndex     HwQueueInd) :
    m_CommandQueueId{CommandQueueId}
{
    const auto& DevInfo      = pDeviceD3D12Impl->GetDeviceInfo();
    auto*       pd3d12Device = pDeviceD3D12Impl->GetD3D12Device();

    Uint32 ResolveBufferOffset = 0;
    for (Uint32 query_type = QUERY_TYPE_UNDEFINED + 1; query_type < QUERY_TYPE_NUM_TYPES; ++query_type)
    {
        const auto QueryType = static_cast<QUERY_TYPE>(query_type);

        // clang-format off
        static_assert(QUERY_TYPE_OCCLUSION          == 1, "Unexpected value of QUERY_TYPE_OCCLUSION. EngineD3D12CreateInfo::QueryPoolSizes must be updated");
        static_assert(QUERY_TYPE_BINARY_OCCLUSION   == 2, "Unexpected value of QUERY_TYPE_BINARY_OCCLUSION. EngineD3D12CreateInfo::QueryPoolSizes must be updated");
        static_assert(QUERY_TYPE_TIMESTAMP          == 3, "Unexpected value of QUERY_TYPE_TIMESTAMP. EngineD3D12CreateInfo::QueryPoolSizes must be updated");
        static_assert(QUERY_TYPE_PIPELINE_STATISTICS== 4, "Unexpected value of QUERY_TYPE_PIPELINE_STATISTICS. EngineD3D12CreateInfo::QueryPoolSizes must be updated");
        static_assert(QUERY_TYPE_DURATION           == 5, "Unexpected value of QUERY_TYPE_DURATION. EngineD3D12CreateInfo::QueryPoolSizes must be updated");
        static_assert(QUERY_TYPE_NUM_TYPES          == 6, "Unexpected value of QUERY_TYPE_NUM_TYPES. EngineD3D12CreateInfo::QueryPoolSizes must be updated");
        // clang-format on

        // Time and duration queries are supported in all queues
        if (QueryType == QUERY_TYPE_TIMESTAMP || QueryType == QUERY_TYPE_DURATION)
        {
            if (HwQueueInd == D3D12HWQueueIndex_Copy && !DevInfo.Features.TransferQueueTimestampQueries)
                continue; // Not supported in transfer queue
        }
        // Other queries are only supported in graphics queue
        else if (HwQueueInd != D3D12HWQueueIndex_Graphics)
            continue;

        D3D12_QUERY_HEAP_DESC d3d12HeapDesc{};
        d3d12HeapDesc.Type  = QueryTypeToD3D12QueryHeapType(QueryType, HwQueueInd);
        d3d12HeapDesc.Count = QueryHeapSizes[QueryType];
        if (QueryType == QUERY_TYPE_DURATION)
            d3d12HeapDesc.Count *= 2;

        auto& HeapInfo = m_Heaps[QueryType];
        HeapInfo.Init(pd3d12Device, d3d12HeapDesc, QueryType, ResolveBufferOffset);
        VERIFY_EXPR(!HeapInfo.IsNull() && HeapInfo.GetType() == QueryType && HeapInfo.GetQueryCount() == d3d12HeapDesc.Count);
    }

    D3D12_RESOURCE_DESC D3D12BuffDesc = {};
    D3D12BuffDesc.Dimension           = D3D12_RESOURCE_DIMENSION_BUFFER;
    D3D12BuffDesc.Alignment           = 0;
    D3D12BuffDesc.Width               = ResolveBufferOffset;
    D3D12BuffDesc.Height              = 1;
    D3D12BuffDesc.DepthOrArraySize    = 1;
    D3D12BuffDesc.MipLevels           = 1;
    D3D12BuffDesc.Format              = DXGI_FORMAT_UNKNOWN;
    D3D12BuffDesc.SampleDesc.Count    = 1;
    D3D12BuffDesc.SampleDesc.Quality  = 0;
    // Layout must be D3D12_TEXTURE_LAYOUT_ROW_MAJOR, as buffer memory layouts are
    // understood by applications and row-major texture data is commonly marshaled through buffers.
    D3D12BuffDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
    D3D12BuffDesc.Flags  = D3D12_RESOURCE_FLAG_NONE;

    D3D12_HEAP_PROPERTIES HeapProps = {};
    HeapProps.Type                  = D3D12_HEAP_TYPE_READBACK;
    HeapProps.CPUPageProperty       = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
    HeapProps.MemoryPoolPreference  = D3D12_MEMORY_POOL_UNKNOWN;
    HeapProps.CreationNodeMask      = 1;
    HeapProps.VisibleNodeMask       = 1;

    // The destination buffer of a query resolve operation must be in the D3D12_RESOURCE_USAGE_COPY_DEST state.
    // ResolveQueryData works with all heap types (default, upload, readback).
    // https://microsoft.github.io/DirectX-Specs/d3d/CountersAndQueries.html#resolvequerydata
    auto hr = pd3d12Device->CreateCommittedResource(&HeapProps, D3D12_HEAP_FLAG_NONE,
                                                    &D3D12BuffDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr,
                                                    __uuidof(m_pd3d12ResolveBuffer),
                                                    reinterpret_cast<void**>(static_cast<ID3D12Resource**>(&m_pd3d12ResolveBuffer)));
    if (FAILED(hr))
        LOG_ERROR_AND_THROW("Failed to create D3D12 resolve buffer");
}

QueryManagerD3D12::~QueryManagerD3D12()
{
    std::stringstream QueryUsageSS;
    QueryUsageSS << "D3D12 query manager peak usage:";

    for (Uint32 query_type = QUERY_TYPE_UNDEFINED + 1; query_type < QUERY_TYPE_NUM_TYPES; ++query_type)
    {
        const auto  QueryType = static_cast<QUERY_TYPE>(query_type);
        const auto& HeapInfo  = m_Heaps[QueryType];
        if (HeapInfo.IsNull())
            continue;

        QueryUsageSS << std::endl
                     << std::setw(30) << std::left << GetQueryTypeString(QueryType) << ": "
                     << std::setw(4) << std::right << HeapInfo.GetMaxAllocatedQueries()
                     << '/' << std::setw(4) << HeapInfo.GetQueryCount();
    }
    LOG_INFO_MESSAGE(QueryUsageSS.str());
}

Uint32 QueryManagerD3D12::AllocateQuery(QUERY_TYPE Type)
{
    return m_Heaps[Type].Allocate();
}

void QueryManagerD3D12::ReleaseQuery(QUERY_TYPE Type, Uint32 Index)
{
    m_Heaps[Type].Release(Index);
}

void QueryManagerD3D12::BeginQuery(CommandContext& Ctx, QUERY_TYPE Type, Uint32 Index) const
{
    const auto  d3d12QueryType = QueryTypeToD3D12QueryType(Type);
    const auto& HeapInfo       = m_Heaps[Type];
    VERIFY_EXPR(HeapInfo.GetType() == Type);
    VERIFY(Index < HeapInfo.GetQueryCount(), "Query index ", Index, " is out of range");

    Ctx.BeginQuery(HeapInfo.GetD3D12QueryHeap(), d3d12QueryType, Index);
}

void QueryManagerD3D12::EndQuery(CommandContext& Ctx, QUERY_TYPE Type, Uint32 Index) const
{
    const auto  d3d12QueryType = QueryTypeToD3D12QueryType(Type);
    const auto& HeapInfo       = m_Heaps[Type];
    VERIFY_EXPR(HeapInfo.GetType() == Type);

    VERIFY(Index < HeapInfo.GetQueryCount(), "Query index ", Index, " is out of range");
    Ctx.EndQuery(HeapInfo.GetD3D12QueryHeap(), d3d12QueryType, Index);

    // https://microsoft.github.io/DirectX-Specs/d3d/CountersAndQueries.html#resolvequerydata
    Ctx.ResolveQueryData(HeapInfo.GetD3D12QueryHeap(), d3d12QueryType, Index, 1, m_pd3d12ResolveBuffer, HeapInfo.GetResolveBufferOffset(Index));
}

void QueryManagerD3D12::ReadQueryData(QUERY_TYPE Type, Uint32 Index, void* pDataPtr, Uint32 DataSize) const
{
    const auto& HeapInfo = m_Heaps[Type];
    VERIFY_EXPR(HeapInfo.GetType() == Type);
    const auto QueryDataSize = GetQueryDataSize(Type);
    VERIFY_EXPR(QueryDataSize == DataSize);
    const auto  Offset = HeapInfo.GetResolveBufferOffset(Index);
    D3D12_RANGE ReadRange;
    ReadRange.Begin = Offset;
    ReadRange.End   = SIZE_T{Offset} + SIZE_T{QueryDataSize};

    void* pBufferData = nullptr;
    // The pointer returned by Map is never offset by any values in pReadRange.
    m_pd3d12ResolveBuffer->Map(0, &ReadRange, &pBufferData);
    memcpy(pDataPtr, reinterpret_cast<const Uint8*>(pBufferData) + Offset, QueryDataSize);
    m_pd3d12ResolveBuffer->Unmap(0, nullptr);
}

} // namespace Diligent
<commit_msg>QueryManagerD3D12: fixed zero-size buffer initialization<commit_after>/*
 *  Copyright 2019-2022 Diligent Graphics LLC
 *  Copyright 2015-2019 Egor Yusov
 *
 *  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.
 *
 *  In no event and under no legal theory, whether in tort (including negligence),
 *  contract, or otherwise, unless required by applicable law (such as deliberate
 *  and grossly negligent acts) or agreed to in writing, shall any Contributor be
 *  liable for any damages, including any direct, indirect, special, incidental,
 *  or consequential damages of any character arising as a result of this License or
 *  out of the use or inability to use the software (including but not limited to damages
 *  for loss of goodwill, work stoppage, computer failure or malfunction, or any and
 *  all other commercial damages or losses), even if such Contributor has been advised
 *  of the possibility of such damages.
 */

#include "pch.h"

#include "QueryManagerD3D12.hpp"

#include <algorithm>

#include "D3D12TypeConversions.hpp"
#include "GraphicsAccessories.hpp"
#include "CommandContext.hpp"
#include "Align.hpp"
#include "RenderDeviceD3D12Impl.hpp"

namespace Diligent
{

static Uint32 GetQueryDataSize(QUERY_TYPE QueryType)
{
    // clang-format off
    switch (QueryType)
    {
        case QUERY_TYPE_OCCLUSION:
        case QUERY_TYPE_BINARY_OCCLUSION:
        case QUERY_TYPE_TIMESTAMP:
        case QUERY_TYPE_DURATION:
            return sizeof(Uint64);
            break;

        case QUERY_TYPE_PIPELINE_STATISTICS:
            return sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS);
            break;

        static_assert(QUERY_TYPE_NUM_TYPES == 6, "Not all QUERY_TYPE enum values are tested");

        default:
            UNEXPECTED("Unexpected query type");
            return 0;
    }
    // clang-format on
}

void QueryManagerD3D12::QueryHeapInfo::Init(ID3D12Device*                pd3d12Device,
                                            const D3D12_QUERY_HEAP_DESC& d3d12HeapDesc,
                                            QUERY_TYPE                   QueryType,
                                            Uint32&                      CurrResolveBufferOffset)
{
    VERIFY_EXPR(!m_pd3d12QueryHeap);

    m_Type       = QueryType;
    m_QueryCount = d3d12HeapDesc.Count;

    auto hr = pd3d12Device->CreateQueryHeap(&d3d12HeapDesc, __uuidof(m_pd3d12QueryHeap), reinterpret_cast<void**>(&m_pd3d12QueryHeap));
    CHECK_D3D_RESULT_THROW(hr, "Failed to create D3D12 query heap");

    // AlignedDestinationBufferOffset must be a multiple of 8 bytes.
    // https://microsoft.github.io/DirectX-Specs/d3d/CountersAndQueries.html#resolvequerydata
    m_AlignedQueryDataSize    = AlignUp(GetQueryDataSize(QueryType), Uint32{8});
    m_ResolveBufferBaseOffset = CurrResolveBufferOffset;
    CurrResolveBufferOffset += m_AlignedQueryDataSize * m_QueryCount;

    m_AvailableQueries.resize(m_QueryCount);
    for (Uint32 i = 0; i < m_QueryCount; ++i)
        m_AvailableQueries[i] = i;
}

Uint32 QueryManagerD3D12::QueryHeapInfo::Allocate()
{
    Uint32 Index = InvalidIndex;

    std::lock_guard<std::mutex> Lock{m_AvailableQueriesMtx};
    if (!m_AvailableQueries.empty())
    {
        Index = m_AvailableQueries.back();
        m_AvailableQueries.pop_back();
        m_MaxAllocatedQueries = std::max(m_MaxAllocatedQueries, m_QueryCount - static_cast<Uint32>(m_AvailableQueries.size()));
    }

    return Index;
}

void QueryManagerD3D12::QueryHeapInfo::Release(Uint32 Index)
{
    VERIFY(Index < m_QueryCount, "Query index ", Index, " is out of range");

    std::lock_guard<std::mutex> Lock{m_AvailableQueriesMtx};
    VERIFY(std::find(m_AvailableQueries.begin(), m_AvailableQueries.end(), Index) == m_AvailableQueries.end(),
           "Index ", Index, " already present in available queries list");
    m_AvailableQueries.push_back(Index);
}

QueryManagerD3D12::QueryHeapInfo::~QueryHeapInfo()
{
    if (m_AvailableQueries.size() != m_QueryCount)
    {
        auto OutstandingQueries = m_QueryCount - m_AvailableQueries.size();
        if (OutstandingQueries == 1)
        {
            LOG_ERROR_MESSAGE("One query of type ", GetQueryTypeString(m_Type),
                              " has not been returned to the query manager");
        }
        else
        {
            LOG_ERROR_MESSAGE(OutstandingQueries, " queries of type ", GetQueryTypeString(m_Type),
                              " have not been returned to the query manager");
        }
    }
}

QueryManagerD3D12::QueryManagerD3D12(RenderDeviceD3D12Impl* pDeviceD3D12Impl,
                                     const Uint32           QueryHeapSizes[],
                                     SoftwareQueueIndex     CommandQueueId,
                                     HardwareQueueIndex     HwQueueInd) :
    m_CommandQueueId{CommandQueueId}
{
    const auto& DevInfo      = pDeviceD3D12Impl->GetDeviceInfo();
    auto*       pd3d12Device = pDeviceD3D12Impl->GetD3D12Device();

    Uint32 ResolveBufferOffset = 0;
    for (Uint32 query_type = QUERY_TYPE_UNDEFINED + 1; query_type < QUERY_TYPE_NUM_TYPES; ++query_type)
    {
        const auto QueryType = static_cast<QUERY_TYPE>(query_type);

        // clang-format off
        static_assert(QUERY_TYPE_OCCLUSION          == 1, "Unexpected value of QUERY_TYPE_OCCLUSION. EngineD3D12CreateInfo::QueryPoolSizes must be updated");
        static_assert(QUERY_TYPE_BINARY_OCCLUSION   == 2, "Unexpected value of QUERY_TYPE_BINARY_OCCLUSION. EngineD3D12CreateInfo::QueryPoolSizes must be updated");
        static_assert(QUERY_TYPE_TIMESTAMP          == 3, "Unexpected value of QUERY_TYPE_TIMESTAMP. EngineD3D12CreateInfo::QueryPoolSizes must be updated");
        static_assert(QUERY_TYPE_PIPELINE_STATISTICS== 4, "Unexpected value of QUERY_TYPE_PIPELINE_STATISTICS. EngineD3D12CreateInfo::QueryPoolSizes must be updated");
        static_assert(QUERY_TYPE_DURATION           == 5, "Unexpected value of QUERY_TYPE_DURATION. EngineD3D12CreateInfo::QueryPoolSizes must be updated");
        static_assert(QUERY_TYPE_NUM_TYPES          == 6, "Unexpected value of QUERY_TYPE_NUM_TYPES. EngineD3D12CreateInfo::QueryPoolSizes must be updated");
        // clang-format on

        // Time and duration queries are supported in all queues
        if (QueryType == QUERY_TYPE_TIMESTAMP || QueryType == QUERY_TYPE_DURATION)
        {
            if (HwQueueInd == D3D12HWQueueIndex_Copy && !DevInfo.Features.TransferQueueTimestampQueries)
                continue; // Not supported in transfer queue
        }
        // Other queries are only supported in graphics queue
        else if (HwQueueInd != D3D12HWQueueIndex_Graphics)
            continue;

        D3D12_QUERY_HEAP_DESC d3d12HeapDesc{};
        d3d12HeapDesc.Type  = QueryTypeToD3D12QueryHeapType(QueryType, HwQueueInd);
        d3d12HeapDesc.Count = QueryHeapSizes[QueryType];
        if (QueryType == QUERY_TYPE_DURATION)
            d3d12HeapDesc.Count *= 2;

        auto& HeapInfo = m_Heaps[QueryType];
        HeapInfo.Init(pd3d12Device, d3d12HeapDesc, QueryType, ResolveBufferOffset);
        VERIFY_EXPR(!HeapInfo.IsNull() && HeapInfo.GetType() == QueryType && HeapInfo.GetQueryCount() == d3d12HeapDesc.Count);
    }

    if (ResolveBufferOffset > 0)
    {
        D3D12_RESOURCE_DESC D3D12BuffDesc{};
        D3D12BuffDesc.Dimension          = D3D12_RESOURCE_DIMENSION_BUFFER;
        D3D12BuffDesc.Alignment          = 0;
        D3D12BuffDesc.Width              = ResolveBufferOffset;
        D3D12BuffDesc.Height             = 1;
        D3D12BuffDesc.DepthOrArraySize   = 1;
        D3D12BuffDesc.MipLevels          = 1;
        D3D12BuffDesc.Format             = DXGI_FORMAT_UNKNOWN;
        D3D12BuffDesc.SampleDesc.Count   = 1;
        D3D12BuffDesc.SampleDesc.Quality = 0;
        // Layout must be D3D12_TEXTURE_LAYOUT_ROW_MAJOR, as buffer memory layouts are
        // understood by applications and row-major texture data is commonly marshaled through buffers.
        D3D12BuffDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
        D3D12BuffDesc.Flags  = D3D12_RESOURCE_FLAG_NONE;

        D3D12_HEAP_PROPERTIES HeapProps{};
        HeapProps.Type                 = D3D12_HEAP_TYPE_READBACK;
        HeapProps.CPUPageProperty      = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
        HeapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
        HeapProps.CreationNodeMask     = 1;
        HeapProps.VisibleNodeMask      = 1;

        // The destination buffer of a query resolve operation must be in the D3D12_RESOURCE_USAGE_COPY_DEST state.
        // ResolveQueryData works with all heap types (default, upload, readback).
        // https://microsoft.github.io/DirectX-Specs/d3d/CountersAndQueries.html#resolvequerydata
        auto hr = pd3d12Device->CreateCommittedResource(&HeapProps, D3D12_HEAP_FLAG_NONE,
                                                        &D3D12BuffDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr,
                                                        __uuidof(m_pd3d12ResolveBuffer),
                                                        reinterpret_cast<void**>(static_cast<ID3D12Resource**>(&m_pd3d12ResolveBuffer)));
        if (FAILED(hr))
            LOG_ERROR_AND_THROW("Failed to create D3D12 resolve buffer");
    }
}

QueryManagerD3D12::~QueryManagerD3D12()
{
    std::stringstream QueryUsageSS;
    QueryUsageSS << "D3D12 query manager peak usage:";

    for (Uint32 query_type = QUERY_TYPE_UNDEFINED + 1; query_type < QUERY_TYPE_NUM_TYPES; ++query_type)
    {
        const auto  QueryType = static_cast<QUERY_TYPE>(query_type);
        const auto& HeapInfo  = m_Heaps[QueryType];
        if (HeapInfo.IsNull())
            continue;

        QueryUsageSS << std::endl
                     << std::setw(30) << std::left << GetQueryTypeString(QueryType) << ": "
                     << std::setw(4) << std::right << HeapInfo.GetMaxAllocatedQueries()
                     << '/' << std::setw(4) << HeapInfo.GetQueryCount();
    }
    LOG_INFO_MESSAGE(QueryUsageSS.str());
}

Uint32 QueryManagerD3D12::AllocateQuery(QUERY_TYPE Type)
{
    return m_Heaps[Type].Allocate();
}

void QueryManagerD3D12::ReleaseQuery(QUERY_TYPE Type, Uint32 Index)
{
    m_Heaps[Type].Release(Index);
}

void QueryManagerD3D12::BeginQuery(CommandContext& Ctx, QUERY_TYPE Type, Uint32 Index) const
{
    const auto  d3d12QueryType = QueryTypeToD3D12QueryType(Type);
    const auto& HeapInfo       = m_Heaps[Type];
    VERIFY_EXPR(HeapInfo.GetType() == Type);
    VERIFY(Index < HeapInfo.GetQueryCount(), "Query index ", Index, " is out of range");

    Ctx.BeginQuery(HeapInfo.GetD3D12QueryHeap(), d3d12QueryType, Index);
}

void QueryManagerD3D12::EndQuery(CommandContext& Ctx, QUERY_TYPE Type, Uint32 Index) const
{
    const auto  d3d12QueryType = QueryTypeToD3D12QueryType(Type);
    const auto& HeapInfo       = m_Heaps[Type];
    VERIFY_EXPR(HeapInfo.GetType() == Type);

    VERIFY(Index < HeapInfo.GetQueryCount(), "Query index ", Index, " is out of range");
    Ctx.EndQuery(HeapInfo.GetD3D12QueryHeap(), d3d12QueryType, Index);

    // https://microsoft.github.io/DirectX-Specs/d3d/CountersAndQueries.html#resolvequerydata
    Ctx.ResolveQueryData(HeapInfo.GetD3D12QueryHeap(), d3d12QueryType, Index, 1, m_pd3d12ResolveBuffer, HeapInfo.GetResolveBufferOffset(Index));
}

void QueryManagerD3D12::ReadQueryData(QUERY_TYPE Type, Uint32 Index, void* pDataPtr, Uint32 DataSize) const
{
    const auto& HeapInfo = m_Heaps[Type];
    VERIFY_EXPR(HeapInfo.GetType() == Type);
    const auto QueryDataSize = GetQueryDataSize(Type);
    VERIFY_EXPR(QueryDataSize == DataSize);
    const auto  Offset = HeapInfo.GetResolveBufferOffset(Index);
    D3D12_RANGE ReadRange;
    ReadRange.Begin = Offset;
    ReadRange.End   = SIZE_T{Offset} + SIZE_T{QueryDataSize};

    void* pBufferData = nullptr;
    // The pointer returned by Map is never offset by any values in pReadRange.
    m_pd3d12ResolveBuffer->Map(0, &ReadRange, &pBufferData);
    memcpy(pDataPtr, reinterpret_cast<const Uint8*>(pBufferData) + Offset, QueryDataSize);
    m_pd3d12ResolveBuffer->Unmap(0, nullptr);
}

} // namespace Diligent
<|endoftext|>


<commit_before>/*=========================================================================

Program:   Visualization Toolkit
Module:    vtkTestHierarchicalDataReader.cxx

Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkTestHierarchicalDataReader.h"

#include "vtkAMRBox.h"
#include "vtkCompositeDataPipeline.h"
#include "vtkExecutive.h"
#include "vtkHierarchicalBoxDataSet.h"
#include "vtkHierarchicalDataInformation.h"
#include "vtkImageData.h"
#include "vtkInformation.h"
#include "vtkInformationIntegerVectorKey.h"
#include "vtkInformationDoubleVectorKey.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkUniformGrid.h"
#include "vtkXMLImageDataReader.h"

vtkCxxRevisionMacro(vtkTestHierarchicalDataReader, "1.6");
vtkStandardNewMacro(vtkTestHierarchicalDataReader);

vtkTestHierarchicalDataReader::vtkTestHierarchicalDataReader()
{
  this->FileName = 0;

  this->SetNumberOfInputPorts(0);
}

vtkTestHierarchicalDataReader::~vtkTestHierarchicalDataReader()
{
  this->SetFileName(0);
}

// Provide information about the dataset:
// * Number of levels
// * Number of boxes / level
// * AMRBox (extent) of each box
int vtkTestHierarchicalDataReader::RequestInformation(
  vtkInformation* request,
  vtkInformationVector** inputVector,
  vtkInformationVector* outputVector)
{
  if (!this->Superclass::RequestInformation(request, inputVector, outputVector))
    {
    return 0;
    }

  const int numLevels = 3;
  int numBlocks[numLevels] = { 1, 1, 14 };

  vtkHierarchicalDataInformation* compInfo =
    vtkHierarchicalDataInformation::New();
  compInfo->SetNumberOfLevels(numLevels);
  int i;
  for (i=0; i<numLevels; i++)
    {
    compInfo->SetNumberOfDataSets(i, numBlocks[i]);
    }

  vtkInformation* info = outputVector->GetInformationObject(0);
  info->Set(
    vtkCompositeDataPipeline::COMPOSITE_DATA_INFORMATION(), compInfo);

  info->Set(
    vtkStreamingDemandDrivenPipeline::MAXIMUM_NUMBER_OF_PIECES(), -1);

  vtkXMLImageDataReader* reader = vtkXMLImageDataReader::New();

  for (i=0; i<16; i++)
    {
    // Here we load the 16 separate files (each containing
    // an image dataset -uniform rectilinear grid-)
    char* fstr = this->GetBlockFileName(i);
    reader->SetFileName(fstr);

    reader->UpdateInformation();

    delete[] fstr;

    // Each sub-dataset in a vtkHierarchicalBoxDataSet has an associated
    // vtkAMRBox. This is similar to extent but is stored externally
    // since it is possible to have sub-dataset nodes with NULL
    // vtkUniformGrid pointers.
    vtkAMRBox box;

    // This is a hack (do not do this at home). Normally, the
    // region (box) information should be available in the file.
    // In this case, since there is no such information available,
    // we obtain it by looking at each image data's extent.
    // -- begin hack
    int extent[6];
    double spacing[3];
    double origin[3];

    vtkInformation* outInfo = reader->GetExecutive()->GetOutputInformation(0);
    outInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), extent);
    outInfo->Get(vtkDataObject::SPACING(), spacing);
    outInfo->Get(vtkDataObject::ORIGIN(), origin);

    int j;
    for (j=0; j<3; j++)
      {
      int num = static_cast<int>(floor(origin[j]/spacing[j] + 0.5));
      box.LoCorner[j] = num + extent[2*j];
      box.HiCorner[j] = num + extent[2*j+1] - 1;
      }

    int level;
    int dsindex;

    this->GetBlockIdx(i, level, dsindex);

    vtkInformation* subInfo = compInfo->GetInformation(level, dsindex);
    subInfo->Set(vtkHierarchicalBoxDataSet::BOX(),
                 box.LoCorner[0], box.LoCorner[1], box.LoCorner[2],
                 box.HiCorner[0], box.HiCorner[1], box.HiCorner[2]);
    }

  reader->Delete();
  compInfo->Delete();

  return 1;
}

int vtkTestHierarchicalDataReader::SetUpdateBlocks(
  vtkInformation*,
  vtkInformationVector**,
  vtkInformationVector* outputVector)
{
  vtkInformation* info = outputVector->GetInformationObject(0);

  if (!info->Has(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()) ||
      !info->Has(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES()))
    {
    vtkErrorMacro("Expected information not found. "
                  "Cannot provide update extent.");
    return 0;
    }

  vtkHierarchicalDataInformation* compInfo =
    vtkHierarchicalDataInformation::SafeDownCast(
      info->Get(vtkCompositeDataPipeline::COMPOSITE_DATA_INFORMATION()));

  if (!compInfo)
    {
    vtkErrorMacro("Expected information not found. "
                  "Cannot provide update extent.");
    return 0;
    }

  vtkHierarchicalDataInformation* updateInfo =
    vtkHierarchicalDataInformation::New();
  info->Set(
    vtkCompositeDataPipeline::UPDATE_BLOCKS(), updateInfo);
  updateInfo->SetNumberOfLevels(compInfo->GetNumberOfLevels());

  unsigned int updatePiece = static_cast<unsigned int>(
    info->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()));
  unsigned int updateNumPieces =  static_cast<unsigned int>(
    info->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES()));

  unsigned int numLevels = updateInfo->GetNumberOfLevels();
  for (unsigned int j=0; j<numLevels; j++)
    {
    updateInfo->SetNumberOfDataSets(j, compInfo->GetNumberOfDataSets(j));
    unsigned int numBlocks = updateInfo->GetNumberOfDataSets(j);
    unsigned int numBlocksPerPiece = 1;
    if (updateNumPieces < numBlocks)
      {
      numBlocksPerPiece = numBlocks / updateNumPieces;
      }
    unsigned int minBlock = numBlocksPerPiece*updatePiece;
    unsigned int maxBlock = numBlocksPerPiece*(updatePiece+1);
    if (updatePiece == updateNumPieces - 1)
      {
      maxBlock = numBlocks;
      }
    for (unsigned int i=minBlock; i<maxBlock; i++)
      {
      vtkInformation* blockInfo = updateInfo->GetInformation(j, i);
      blockInfo->Set(vtkCompositeDataPipeline::MARKED_FOR_UPDATE(), 1);
      }
    }
  updateInfo->Delete();
  return 1;
}

int vtkTestHierarchicalDataReader::RequestData(
  vtkInformation*, vtkInformationVector**, vtkInformationVector* outputVector)
{
  int i;

  if (!this->FileName)
    {
    return 0;
    }

  vtkInformation* info = outputVector->GetInformationObject(0);

  vtkDataObject* doOutput =
    info->Get(vtkCompositeDataSet::COMPOSITE_DATA_SET());
  vtkHierarchicalBoxDataSet* hb =
    vtkHierarchicalBoxDataSet::SafeDownCast(doOutput);
  if (!hb)
    {
    return 0;
    }

  vtkHierarchicalDataInformation* compInfo =
    vtkHierarchicalDataInformation::SafeDownCast(
      info->Get(vtkCompositeDataPipeline::COMPOSITE_DATA_INFORMATION()));

  hb->SetHierarchicalDataInformation(compInfo);

  // Since there is no AMR reader avaible yet, we will load a
  // collection of VTK files and create our own vtkHierarchicalBoxDataSet.
  // To create the files, I loaded a Chombo file with an experimental
  // Chombo reader and wrote the datasets separately.
  vtkXMLImageDataReader* reader = vtkXMLImageDataReader::New();

  for (i=0; i<16; i++)
    {
    // Here we load the 16 separate files (each containing
    // an image dataset -uniform rectilinear grid-)
    char* fstr = this->GetBlockFileName(i);
    reader->SetFileName(fstr);

    // We have to update since we are working without a VTK pipeline.
    // This will read the file and the output of the reader will be
    // a valid image data.
    reader->Update();
    delete[] fstr;

    // We now create a vtkUniformGrid. This is essentially a simple
    // vtkImageData (not a sub-class though) with blanking. Since
    // VTK readers do not know vtkUniformGrid, we simply create our
    // own by copying from the image data.
    vtkUniformGrid* ug = vtkUniformGrid::New();
    ug->ShallowCopy(reader->GetOutput());

    int level;
    int dsindex;

    this->GetBlockIdx(i, level, dsindex);

    // Given the level, index and box, add the sub-dataset to
    // hierarchical dataset.
    hb->SetDataSet(level, dsindex, ug);

    ug->Delete();
    }
  reader->Delete();

  // I hard-coded the refinement ratios. These should normally
  // be available in the file.
  hb->SetRefinementRatio(0, 2);
  hb->SetRefinementRatio(1, 2);

  // This call generates visibility (blanking) arrays that mask
  // regions of lower level datasets that overlap with regions
  // of higher level datasets (it is assumed that, when available,
  // higher level information should always be used instead of
  // lower level information)
  hb->GenerateVisibilityArrays();

  return 1;
}

void vtkTestHierarchicalDataReader::GetBlockIdx(
  int blockId, int& level, int& dsindex)
{
  // Similarly, the level of each sub-dataset is normally
  // available in the file. Since this is not the case, I
  // hard-coded this into the example program.
  // Level 0 = { 0 }, Level 1 = { 1 },
  // Level 2 = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }
  if (blockId == 0)
    {
    level = 0;
    dsindex = 0;
    }
  else if (blockId == 1)
    {
    level = 1;
    dsindex = 0;
    }
  else
    {
    level = 2;
    dsindex = blockId-2;
    }
}

char* vtkTestHierarchicalDataReader::GetBlockFileName(int blockId)
{
  size_t len = strlen(this->FileName);
  size_t pos;
  for (pos=0; pos<len; pos++)
    {
    if (this->FileName[pos] == '.')
      {
      break;
      }
    }

  char* fname = new char[pos+1];
  strncpy(fname, this->FileName, pos);
  fname[pos] = '\0';

  // Here we load the 16 separate files (each containing
  // an image dataset -uniform rectilinear grid-)
  char* fstr = new char [strlen(fname) +
                         strlen(".vti") + 10];
  sprintf(fstr,"%s_%i.vti",fname, blockId);
  delete[] fname;

  return fstr;
}

int vtkTestHierarchicalDataReader::FillOutputPortInformation(
  int vtkNotUsed(port), vtkInformation* info)
{
  info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkDataObject");
  info->Set(vtkCompositeDataPipeline::COMPOSITE_DATA_TYPE_NAME(),
            "vtkHierarchicalBoxDataSet");
  return 1;
}

void vtkTestHierarchicalDataReader::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "File Name: " <<
    (this->FileName ? this->FileName : "(none)") << "\n";
}

<commit_msg>COMP: Fix several test failures and warnings for VJ dashboards... Details, including comments and related file lists, follow.<commit_after>/*=========================================================================

Program:   Visualization Toolkit
Module:    vtkTestHierarchicalDataReader.cxx

Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkTestHierarchicalDataReader.h"

#include "vtkAMRBox.h"
#include "vtkCompositeDataPipeline.h"
#include "vtkExecutive.h"
#include "vtkHierarchicalBoxDataSet.h"
#include "vtkHierarchicalDataInformation.h"
#include "vtkImageData.h"
#include "vtkInformation.h"
#include "vtkInformationIntegerVectorKey.h"
#include "vtkInformationDoubleVectorKey.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkUniformGrid.h"
#include "vtkXMLImageDataReader.h"

vtkCxxRevisionMacro(vtkTestHierarchicalDataReader, "1.7");
vtkStandardNewMacro(vtkTestHierarchicalDataReader);

vtkTestHierarchicalDataReader::vtkTestHierarchicalDataReader()
{
  this->FileName = 0;

  this->SetNumberOfInputPorts(0);
}

vtkTestHierarchicalDataReader::~vtkTestHierarchicalDataReader()
{
  this->SetFileName(0);
}

// Provide information about the dataset:
// * Number of levels
// * Number of boxes / level
// * AMRBox (extent) of each box
int vtkTestHierarchicalDataReader::RequestInformation(
  vtkInformation* request,
  vtkInformationVector** inputVector,
  vtkInformationVector* outputVector)
{
  if (!this->Superclass::RequestInformation(request, inputVector, outputVector))
    {
    return 0;
    }

  const int numLevels = 3;
  int numBlocks[numLevels] = { 1, 1, 14 };

  vtkHierarchicalDataInformation* compInfo =
    vtkHierarchicalDataInformation::New();
  compInfo->SetNumberOfLevels(numLevels);
  int i;
  for (i=0; i<numLevels; i++)
    {
    compInfo->SetNumberOfDataSets(i, numBlocks[i]);
    }

  vtkInformation* info = outputVector->GetInformationObject(0);
  info->Set(
    vtkCompositeDataPipeline::COMPOSITE_DATA_INFORMATION(), compInfo);

  info->Set(
    vtkStreamingDemandDrivenPipeline::MAXIMUM_NUMBER_OF_PIECES(), -1);

  vtkXMLImageDataReader* reader = vtkXMLImageDataReader::New();

  for (i=0; i<16; i++)
    {
    // Here we load the 16 separate files (each containing
    // an image dataset -uniform rectilinear grid-)
    char* fstr = this->GetBlockFileName(i);
    reader->SetFileName(fstr);

    reader->UpdateInformation();

    delete[] fstr;

    // Each sub-dataset in a vtkHierarchicalBoxDataSet has an associated
    // vtkAMRBox. This is similar to extent but is stored externally
    // since it is possible to have sub-dataset nodes with NULL
    // vtkUniformGrid pointers.
    vtkAMRBox box;

    // This is a hack (do not do this at home). Normally, the
    // region (box) information should be available in the file.
    // In this case, since there is no such information available,
    // we obtain it by looking at each image data's extent.
    // -- begin hack
    int extent[6];
    double spacing[3];
    double origin[3];

    vtkInformation* outInfo = reader->GetExecutive()->GetOutputInformation(0);
    outInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), extent);
    outInfo->Get(vtkDataObject::SPACING(), spacing);
    outInfo->Get(vtkDataObject::ORIGIN(), origin);

    int j;
    for (j=0; j<3; j++)
      {
      int num = static_cast<int>(floor(origin[j]/spacing[j] + 0.5));
      box.LoCorner[j] = num + extent[2*j];
      box.HiCorner[j] = num + extent[2*j+1] - 1;
      }

    int level;
    int dsindex;

    this->GetBlockIdx(i, level, dsindex);

    vtkInformation* subInfo = compInfo->GetInformation(level, dsindex);
    subInfo->Set(vtkHierarchicalBoxDataSet::BOX(),
                 box.LoCorner[0], box.LoCorner[1], box.LoCorner[2],
                 box.HiCorner[0], box.HiCorner[1], box.HiCorner[2]);
    }

  reader->Delete();
  compInfo->Delete();

  return 1;
}

int vtkTestHierarchicalDataReader::SetUpdateBlocks(
  vtkInformation*,
  vtkInformationVector**,
  vtkInformationVector* outputVector)
{
  vtkInformation* info = outputVector->GetInformationObject(0);

  if (!info->Has(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()) ||
      !info->Has(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES()))
    {
    vtkErrorMacro("Expected information not found. "
                  "Cannot provide update extent.");
    return 0;
    }

  vtkHierarchicalDataInformation* compInfo =
    vtkHierarchicalDataInformation::SafeDownCast(
      info->Get(vtkCompositeDataPipeline::COMPOSITE_DATA_INFORMATION()));

  if (!compInfo)
    {
    vtkErrorMacro("Expected information not found. "
                  "Cannot provide update extent.");
    return 0;
    }

  vtkHierarchicalDataInformation* updateInfo =
    vtkHierarchicalDataInformation::New();
  info->Set(
    vtkCompositeDataPipeline::UPDATE_BLOCKS(), updateInfo);
  updateInfo->SetNumberOfLevels(compInfo->GetNumberOfLevels());

  unsigned int updatePiece = static_cast<unsigned int>(
    info->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()));
  unsigned int updateNumPieces =  static_cast<unsigned int>(
    info->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES()));

  unsigned int numLevels = updateInfo->GetNumberOfLevels();
  for (unsigned int j=0; j<numLevels; j++)
    {
    updateInfo->SetNumberOfDataSets(j, compInfo->GetNumberOfDataSets(j));
    unsigned int numBlocks = updateInfo->GetNumberOfDataSets(j);
    unsigned int numBlocksPerPiece = 1;
    if (updateNumPieces < numBlocks)
      {
      numBlocksPerPiece = numBlocks / updateNumPieces;
      }
    unsigned int minBlock = numBlocksPerPiece*updatePiece;
    unsigned int maxBlock = numBlocksPerPiece*(updatePiece+1);
    if (updatePiece == updateNumPieces - 1)
      {
      maxBlock = numBlocks;
      }
    for (unsigned int i=minBlock; i<maxBlock; i++)
      {
      vtkInformation* blockInfo = updateInfo->GetInformation(j, i);
      blockInfo->Set(vtkCompositeDataPipeline::MARKED_FOR_UPDATE(), 1);
      }
    }
  updateInfo->Delete();
  return 1;
}

int vtkTestHierarchicalDataReader::RequestData(
  vtkInformation*, vtkInformationVector**, vtkInformationVector* outputVector)
{
  int i;

  if (!this->FileName)
    {
    return 0;
    }

  vtkInformation* info = outputVector->GetInformationObject(0);

  vtkDataObject* doOutput =
    info->Get(vtkCompositeDataSet::COMPOSITE_DATA_SET());
  vtkHierarchicalBoxDataSet* hb =
    vtkHierarchicalBoxDataSet::SafeDownCast(doOutput);
  if (!hb)
    {
    return 0;
    }

  vtkHierarchicalDataInformation* compInfo =
    vtkHierarchicalDataInformation::SafeDownCast(
      info->Get(vtkCompositeDataPipeline::COMPOSITE_DATA_INFORMATION()));

  hb->SetHierarchicalDataInformation(compInfo);

  // Since there is no AMR reader avaible yet, we will load a
  // collection of VTK files and create our own vtkHierarchicalBoxDataSet.
  // To create the files, I loaded a Chombo file with an experimental
  // Chombo reader and wrote the datasets separately.
  vtkXMLImageDataReader* reader = vtkXMLImageDataReader::New();

  for (i=0; i<16; i++)
    {
    // Here we load the 16 separate files (each containing
    // an image dataset -uniform rectilinear grid-)
    char* fstr = this->GetBlockFileName(i);
    reader->SetFileName(fstr);

    // We have to update since we are working without a VTK pipeline.
    // This will read the file and the output of the reader will be
    // a valid image data.
    reader->Update();
    delete[] fstr;

    // We now create a vtkUniformGrid. This is essentially a simple
    // vtkImageData (not a sub-class though) with blanking. Since
    // VTK readers do not know vtkUniformGrid, we simply create our
    // own by copying from the image data.
    vtkUniformGrid* ug = vtkUniformGrid::New();
    ug->ShallowCopy(reader->GetOutput());

    int level;
    int dsindex;

    this->GetBlockIdx(i, level, dsindex);

    // Given the level, index and box, add the sub-dataset to
    // hierarchical dataset.
    hb->SetDataSet(level, dsindex, ug);

    ug->Delete();
    }
  reader->Delete();

  // I hard-coded the refinement ratios. These should normally
  // be available in the file.
  hb->SetRefinementRatio(0, 2);
  hb->SetRefinementRatio(1, 2);

  // This call generates visibility (blanking) arrays that mask
  // regions of lower level datasets that overlap with regions
  // of higher level datasets (it is assumed that, when available,
  // higher level information should always be used instead of
  // lower level information)
  hb->GenerateVisibilityArrays();

  return 1;
}

void vtkTestHierarchicalDataReader::GetBlockIdx(
  int blockId, int& level, int& dsindex)
{
  // Similarly, the level of each sub-dataset is normally
  // available in the file. Since this is not the case, I
  // hard-coded this into the example program.
  // Level 0 = { 0 }, Level 1 = { 1 },
  // Level 2 = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }
  if (blockId == 0)
    {
    level = 0;
    dsindex = 0;
    }
  else if (blockId == 1)
    {
    level = 1;
    dsindex = 0;
    }
  else
    {
    level = 2;
    dsindex = blockId-2;
    }
}

char* vtkTestHierarchicalDataReader::GetBlockFileName(int blockId)
{
  size_t len = strlen(this->FileName);
  size_t pos;

  // Search from the tail end of the filename until we
  // find a '.' indicating an extension, or we find a
  // path separator or the beginning of the string.
  for (pos=len-1; pos!=0; --pos)
    {
    if (this->FileName[pos] == '.')
      {
      break;
      }

    if (1==pos || this->FileName[pos] == '/')
      {
      // No extension on this->FileName; use the whole
      // thing as the base name
      pos= len;
      break;
      }
    }

  char* fname = new char[pos+1];
  strncpy(fname, this->FileName, pos);
  fname[pos] = '\0';

  // Here we load the 16 separate files (each containing
  // an image dataset -uniform rectilinear grid-)
  char* fstr = new char [strlen(fname) +
                         strlen(".vti") + 10];
  sprintf(fstr,"%s_%i.vti",fname, blockId);
  delete[] fname;

  return fstr;
}

int vtkTestHierarchicalDataReader::FillOutputPortInformation(
  int vtkNotUsed(port), vtkInformation* info)
{
  info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkDataObject");
  info->Set(vtkCompositeDataPipeline::COMPOSITE_DATA_TYPE_NAME(),
            "vtkHierarchicalBoxDataSet");
  return 1;
}

void vtkTestHierarchicalDataReader::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "File Name: " <<
    (this->FileName ? this->FileName : "(none)") << "\n";
}

<|endoftext|>