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

  Program:   Visualization Toolkit
  Module:    vtkScalarBarRepresentation.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.

=========================================================================*/

/*
 * Copyright 2008 Sandia Corporation.
 * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
 * license for use of this work by or on behalf of the
 * U.S. Government. Redistribution and use in source and binary forms, with
 * or without modification, are permitted provided that this Notice and any
 * statement of authorship are reproduced on all copies.
 */

#include "vtkScalarBarRepresentation.h"

#include "vtkObjectFactory.h"
#include "vtkPropCollection.h"
#include "vtkScalarBarActor.h"
#include "vtkSmartPointer.h"
#include "vtkTextProperty.h"

#include <algorithm>

//=============================================================================
vtkStandardNewMacro(vtkScalarBarRepresentation);
//-----------------------------------------------------------------------------
vtkScalarBarRepresentation::vtkScalarBarRepresentation()
{
  this->PositionCoordinate->SetValue(0.82, 0.1);
  this->Position2Coordinate->SetValue(0.17, 0.8);

  this->ScalarBarActor = NULL;
  vtkScalarBarActor *actor = vtkScalarBarActor::New();
  this->SetScalarBarActor(actor);
  actor->Delete();

  this->SetShowBorder(vtkBorderRepresentation::BORDER_ACTIVE);
}

//-----------------------------------------------------------------------------
vtkScalarBarRepresentation::~vtkScalarBarRepresentation()
{
  this->SetScalarBarActor(NULL);
}

//-----------------------------------------------------------------------------
void vtkScalarBarRepresentation::SetScalarBarActor(vtkScalarBarActor* actor)
{
  if (this->ScalarBarActor != actor)
    {
    vtkSmartPointer<vtkScalarBarActor> oldActor = this->ScalarBarActor;
    vtkSetObjectBodyMacro(ScalarBarActor, vtkScalarBarActor, actor);
    if (actor && oldActor)
      {
      actor->SetOrientation(oldActor->GetOrientation());
      }
    }
}

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

  os << indent << "ScalarBarActor: " << this->ScalarBarActor << endl;
}

//-----------------------------------------------------------------------------
void vtkScalarBarRepresentation::SetOrientation(int orientation)
{
  if (this->ScalarBarActor)
    {
    this->ScalarBarActor->SetOrientation(orientation);
    }
}

//-----------------------------------------------------------------------------
int vtkScalarBarRepresentation::GetOrientation()
{
  if (this->ScalarBarActor)
    {
    return this->ScalarBarActor->GetOrientation();
    }
  vtkErrorMacro("No scalar bar");
  return 0;
}

//-----------------------------------------------------------------------------
void vtkScalarBarRepresentation::BuildRepresentation()
{
  if (this->ScalarBarActor)
    {
    this->ScalarBarActor->SetPosition(this->GetPosition());
    this->ScalarBarActor->SetPosition2(this->GetPosition2());
    }

  this->Superclass::BuildRepresentation();
}

//-----------------------------------------------------------------------------
void vtkScalarBarRepresentation::WidgetInteraction(double eventPos[2])
{
  // Let superclass move things around.
  this->Superclass::WidgetInteraction(eventPos);

  // Check to see if we need to change the orientation.
  double *fpos1 = this->PositionCoordinate->GetValue();
  double *fpos2 = this->Position2Coordinate->GetValue();
  double par1[2];
  double par2[2];
  par1[0] = fpos1[0];
  par1[1] = fpos1[1];
  par2[0] = fpos1[0] + fpos2[0];
  par2[1] = fpos1[1] + fpos2[1];
  double center[2];
  center[0] = fpos1[0] + 0.5*fpos2[0];
  center[1] = fpos1[1] + 0.5*fpos2[1];
  bool orientationSwapped = false;
  if (fabs(center[0] - 0.5) > 0.2+fabs(center[1] - 0.5))
    {
    // Close enough to left/right to be swapped to vertical
    if (this->ScalarBarActor->GetOrientation() == VTK_ORIENT_HORIZONTAL)
      {
      this->ScalarBarActor->SetOrientation(VTK_ORIENT_VERTICAL);
      orientationSwapped = true;
      }
    }
  else if (fabs(center[1] - 0.5) > 0.2+fabs(center[0] - 0.5))
    {
    // Close enough to left/right to be swapped to horizontal
    if (this->ScalarBarActor->GetOrientation() == VTK_ORIENT_VERTICAL)
      {
      this->ScalarBarActor->SetOrientation(VTK_ORIENT_HORIZONTAL);
      orientationSwapped = true;
      }
    }

  if (orientationSwapped)
    {
    // Change the corners to effectively rotate 90 degrees.
    par2[0] = center[0] + center[1] - par1[1];
    par2[1] = center[1] + center[0] - par1[0];
    par1[0] = 2*center[0] - par2[0];
    par1[1] = 2*center[1] - par2[1];

    this->PositionCoordinate->SetValue(par1[0],par1[1]);
    this->Position2Coordinate->SetValue(par2[0] - par1[0], par2[1] - par1[1]);

    std::swap(this->ShowHorizontalBorder, this->ShowVerticalBorder);

    this->Modified();
    this->UpdateShowBorder();
    this->BuildRepresentation();
  }
}

//-----------------------------------------------------------------------------
int vtkScalarBarRepresentation::GetVisibility()
{
  return this->ScalarBarActor->GetVisibility();
}

//-----------------------------------------------------------------------------
void vtkScalarBarRepresentation::SetVisibility(int vis)
{
  this->ScalarBarActor->SetVisibility(vis);
}

//-----------------------------------------------------------------------------
void vtkScalarBarRepresentation::GetActors2D(vtkPropCollection *collection)
{
  if (this->ScalarBarActor)
    {
    collection->AddItem(this->ScalarBarActor);
    }
  this->Superclass::GetActors2D(collection);
}

//-----------------------------------------------------------------------------
void vtkScalarBarRepresentation::ReleaseGraphicsResources(vtkWindow *w)
{
  if (this->ScalarBarActor)
    {
    this->ScalarBarActor->ReleaseGraphicsResources(w);
    }
  this->Superclass::ReleaseGraphicsResources(w);
}

//-------------------------------------------------------------------------
int vtkScalarBarRepresentation::RenderOverlay(vtkViewport *w)
{
  int count = this->Superclass::RenderOverlay(w);
  if (this->ScalarBarActor)
    {
    count += this->ScalarBarActor->RenderOverlay(w);
    }
  return count;
}

//-------------------------------------------------------------------------
int vtkScalarBarRepresentation::RenderOpaqueGeometry(vtkViewport *w)
{
  int count = this->Superclass::RenderOpaqueGeometry(w);
  if (this->ScalarBarActor)
    {
    count += this->ScalarBarActor->RenderOpaqueGeometry(w);
    }
  return count;
}

//-------------------------------------------------------------------------
int vtkScalarBarRepresentation::RenderTranslucentPolygonalGeometry(
                                                                 vtkViewport *w)
{
  int count = this->Superclass::RenderTranslucentPolygonalGeometry(w);
  if (this->ScalarBarActor)
    {
    count += this->ScalarBarActor->RenderTranslucentPolygonalGeometry(w);
    }
  return count;
}

//-------------------------------------------------------------------------
int vtkScalarBarRepresentation::HasTranslucentPolygonalGeometry()
{
  int result = this->Superclass::HasTranslucentPolygonalGeometry();
  if (this->ScalarBarActor)
    {
    result |= this->ScalarBarActor->HasTranslucentPolygonalGeometry();
    }
  return result;
}

<commit_msg>BUG: Border visibility from underlying vtkScalarBar actor<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkScalarBarRepresentation.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.

=========================================================================*/

/*
 * Copyright 2008 Sandia Corporation.
 * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
 * license for use of this work by or on behalf of the
 * U.S. Government. Redistribution and use in source and binary forms, with
 * or without modification, are permitted provided that this Notice and any
 * statement of authorship are reproduced on all copies.
 */

#include "vtkScalarBarRepresentation.h"

#include "vtkObjectFactory.h"
#include "vtkPropCollection.h"
#include "vtkScalarBarActor.h"
#include "vtkSmartPointer.h"
#include "vtkTextProperty.h"

#include <algorithm>

//=============================================================================
vtkStandardNewMacro(vtkScalarBarRepresentation);
//-----------------------------------------------------------------------------
vtkScalarBarRepresentation::vtkScalarBarRepresentation()
{
  this->PositionCoordinate->SetValue(0.82, 0.1);
  this->Position2Coordinate->SetValue(0.17, 0.8);

  this->ScalarBarActor = NULL;
  vtkScalarBarActor *actor = vtkScalarBarActor::New();
  this->SetScalarBarActor(actor);
  actor->Delete();

  this->SetShowBorder(vtkBorderRepresentation::BORDER_ACTIVE);
}

//-----------------------------------------------------------------------------
vtkScalarBarRepresentation::~vtkScalarBarRepresentation()
{
  this->SetScalarBarActor(NULL);
}

//-----------------------------------------------------------------------------
void vtkScalarBarRepresentation::SetScalarBarActor(vtkScalarBarActor* actor)
{
  if (this->ScalarBarActor != actor)
    {
    vtkSmartPointer<vtkScalarBarActor> oldActor = this->ScalarBarActor;
    vtkSetObjectBodyMacro(ScalarBarActor, vtkScalarBarActor, actor);
    if (actor && oldActor)
      {
      actor->SetOrientation(oldActor->GetOrientation());
      if(actor->GetOrientation())
        {
        this->ShowHorizontalBorder = 2;
        this->ShowVerticalBorder = 0;
        }
      else
        {
        this->ShowHorizontalBorder = 0;
        this->ShowVerticalBorder = 2;
        }
      this->UpdateShowBorder();
      }
    }
}

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

  os << indent << "ScalarBarActor: " << this->ScalarBarActor << endl;
}

//-----------------------------------------------------------------------------
void vtkScalarBarRepresentation::SetOrientation(int orientation)
{
  if (this->ScalarBarActor)
    {
    this->ScalarBarActor->SetOrientation(orientation);
    }
}

//-----------------------------------------------------------------------------
int vtkScalarBarRepresentation::GetOrientation()
{
  if (this->ScalarBarActor)
    {
    return this->ScalarBarActor->GetOrientation();
    }
  vtkErrorMacro("No scalar bar");
  return 0;
}

//-----------------------------------------------------------------------------
void vtkScalarBarRepresentation::BuildRepresentation()
{
  if (this->ScalarBarActor)
    {
    this->ScalarBarActor->SetPosition(this->GetPosition());
    this->ScalarBarActor->SetPosition2(this->GetPosition2());
    }

  this->Superclass::BuildRepresentation();
}

//-----------------------------------------------------------------------------
void vtkScalarBarRepresentation::WidgetInteraction(double eventPos[2])
{
  // Let superclass move things around.
  this->Superclass::WidgetInteraction(eventPos);

  // Check to see if we need to change the orientation.
  double *fpos1 = this->PositionCoordinate->GetValue();
  double *fpos2 = this->Position2Coordinate->GetValue();
  double par1[2];
  double par2[2];
  par1[0] = fpos1[0];
  par1[1] = fpos1[1];
  par2[0] = fpos1[0] + fpos2[0];
  par2[1] = fpos1[1] + fpos2[1];
  double center[2];
  center[0] = fpos1[0] + 0.5*fpos2[0];
  center[1] = fpos1[1] + 0.5*fpos2[1];
  bool orientationSwapped = false;
  if (fabs(center[0] - 0.5) > 0.2+fabs(center[1] - 0.5))
    {
    // Close enough to left/right to be swapped to vertical
    if (this->ScalarBarActor->GetOrientation() == VTK_ORIENT_HORIZONTAL)
      {
      this->ScalarBarActor->SetOrientation(VTK_ORIENT_VERTICAL);
      orientationSwapped = true;
      }
    }
  else if (fabs(center[1] - 0.5) > 0.2+fabs(center[0] - 0.5))
    {
    // Close enough to left/right to be swapped to horizontal
    if (this->ScalarBarActor->GetOrientation() == VTK_ORIENT_VERTICAL)
      {
      this->ScalarBarActor->SetOrientation(VTK_ORIENT_HORIZONTAL);
      orientationSwapped = true;
      }
    }

  if (orientationSwapped)
    {
    // Change the corners to effectively rotate 90 degrees.
    par2[0] = center[0] + center[1] - par1[1];
    par2[1] = center[1] + center[0] - par1[0];
    par1[0] = 2*center[0] - par2[0];
    par1[1] = 2*center[1] - par2[1];

    this->PositionCoordinate->SetValue(par1[0],par1[1]);
    this->Position2Coordinate->SetValue(par2[0] - par1[0], par2[1] - par1[1]);

    std::swap(this->ShowHorizontalBorder, this->ShowVerticalBorder);

    this->Modified();
    this->UpdateShowBorder();
    this->BuildRepresentation();
  }
}

//-----------------------------------------------------------------------------
int vtkScalarBarRepresentation::GetVisibility()
{
  return this->ScalarBarActor->GetVisibility();
}

//-----------------------------------------------------------------------------
void vtkScalarBarRepresentation::SetVisibility(int vis)
{
  this->ScalarBarActor->SetVisibility(vis);
}

//-----------------------------------------------------------------------------
void vtkScalarBarRepresentation::GetActors2D(vtkPropCollection *collection)
{
  if (this->ScalarBarActor)
    {
    collection->AddItem(this->ScalarBarActor);
    }
  this->Superclass::GetActors2D(collection);
}

//-----------------------------------------------------------------------------
void vtkScalarBarRepresentation::ReleaseGraphicsResources(vtkWindow *w)
{
  if (this->ScalarBarActor)
    {
    this->ScalarBarActor->ReleaseGraphicsResources(w);
    }
  this->Superclass::ReleaseGraphicsResources(w);
}

//-------------------------------------------------------------------------
int vtkScalarBarRepresentation::RenderOverlay(vtkViewport *w)
{
  int count = this->Superclass::RenderOverlay(w);
  if (this->ScalarBarActor)
    {
    count += this->ScalarBarActor->RenderOverlay(w);
    }
  return count;
}

//-------------------------------------------------------------------------
int vtkScalarBarRepresentation::RenderOpaqueGeometry(vtkViewport *w)
{
  int count = this->Superclass::RenderOpaqueGeometry(w);
  if (this->ScalarBarActor)
    {
    count += this->ScalarBarActor->RenderOpaqueGeometry(w);
    }
  return count;
}

//-------------------------------------------------------------------------
int vtkScalarBarRepresentation::RenderTranslucentPolygonalGeometry(
                                                                 vtkViewport *w)
{
  int count = this->Superclass::RenderTranslucentPolygonalGeometry(w);
  if (this->ScalarBarActor)
    {
    count += this->ScalarBarActor->RenderTranslucentPolygonalGeometry(w);
    }
  return count;
}

//-------------------------------------------------------------------------
int vtkScalarBarRepresentation::HasTranslucentPolygonalGeometry()
{
  int result = this->Superclass::HasTranslucentPolygonalGeometry();
  if (this->ScalarBarActor)
    {
    result |= this->ScalarBarActor->HasTranslucentPolygonalGeometry();
    }
  return result;
}

<|endoftext|>


<commit_before>#include <cstdlib>
#include <type_traits>

#include "benchmark/benchmark_api.h"
#include "test_configs.h"
#include "test_utils.h"

// qsort
void BM_sort(benchmark::State& state) {
  int N = state.range(0);
  c_alloc<int> a(N);
  fill_seq<int*>(a, a+N);
  while (state.KeepRunning()) {
    // searching for all the elements.
    for (int i = 0; i < N; ++i)
      qsort(a.get(), N, sizeof (int), compare<int>);
  }
  state.SetComplexityN(N);
}

// Linear search on a sequence
void BM_search_linear(benchmark::State& state) {
  int N = state.range(0);
  c_alloc<int> a(N);
  fill_seq<int*>(a, a+N);
  while (state.KeepRunning()) {
    // searching for all the elements.
    for (int i = 0; i < N; ++i) {
      int j = 0;
      while (j < N)
        if (a[j++] == i)
          break;
      benchmark::DoNotOptimize(j);
      assert(j == i); // j is the i-th element in a
    }
  }
  state.SetComplexityN(N);
}

// Binary search on a sequence
void BM_search_binary(benchmark::State& state) {
  int N = state.range(0);
  c_alloc<int> a(N);
  fill_seq<int*>(a, a+N);
  while (state.KeepRunning()) {
    // searching for all the elements.
    for (int i = 0; i < N; ++i) {
      int *p = (int*) bsearch(&i, a, N, sizeof (int), compare<int>);
      benchmark::DoNotOptimize(p);
      assert(*p == i); // j is the i-th element in a
    }
  }
  state.SetComplexityN(N);
}

static const int MSize = L1;
COMPLEXITY_BENCHMARK(BM_search_linear, MSize);
COMPLEXITY_BENCHMARK(BM_search_binary, MSize);
COMPLEXITY_BENCHMARK(BM_sort, MSize);
BENCHMARK_MAIN()
<commit_msg>abstract type to scale for multiple types<commit_after>#include <cstdlib>
#include <type_traits>

#include "benchmark/benchmark_api.h"
#include "test_configs.h"
#include "test_utils.h"

// qsort
template<typename T>
void BM_sort(benchmark::State& state) {
  int N = state.range(0);
  c_alloc<T> a(N);
  fill_seq<T*>(a, a+N);
  while (state.KeepRunning()) {
    // searching for all the elements.
    for (int i = 0; i < N; ++i)
      qsort(a.get(), N, sizeof (T), compare<T>);
  }
  state.SetComplexityN(N);
}

// Linear search on a sequence
template<typename T>
void BM_search_linear(benchmark::State& state) {
  int N = state.range(0);
  c_alloc<T> a(N);
  fill_seq<T*>(a, a+N);
  while (state.KeepRunning()) {
    // searching for all the elements.
    for (int i = 0; i < N; ++i) {
      int j = 0;
      while (j < N)
        if (a[j++] == i)
          break;
      benchmark::DoNotOptimize(j);
      assert(j == i); // j is the i-th element in a
    }
  }
  state.SetComplexityN(N);
}

// Binary search on a sequence
template<typename T>
void BM_search_binary(benchmark::State& state) {
  int N = state.range(0);
  c_alloc<T> a(N);
  fill_seq<T*>(a, a+N);
  while (state.KeepRunning()) {
    // searching for all the elements.
    for (int i = 0; i < N; ++i) {
      T *p = (T*) bsearch(&i, a, N, sizeof (T), compare<T>);
      benchmark::DoNotOptimize(p);
      assert(*p == i); // j is the i-th element in a
    }
  }
  state.SetComplexityN(N);
}

static const int MSize = L1;
COMPLEXITY_BENCHMARK_GEN(BM_search_linear, int, MSize);
COMPLEXITY_BENCHMARK_GEN(BM_search_linear, char, MSize);
COMPLEXITY_BENCHMARK_GEN(BM_search_binary, int, MSize);
COMPLEXITY_BENCHMARK_GEN(BM_search_binary, char, MSize);
COMPLEXITY_BENCHMARK_GEN(BM_sort, int, MSize);
COMPLEXITY_BENCHMARK_GEN(BM_sort, char, MSize);
BENCHMARK_MAIN()
<|endoftext|>


<commit_before>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrConfigConversionEffect.h"
#include "GrContext.h"
#include "GrDrawContext.h"
#include "GrInvariantOutput.h"
#include "GrSimpleTextureEffect.h"
#include "SkMatrix.h"
#include "gl/GrGLFragmentProcessor.h"
#include "gl/builders/GrGLProgramBuilder.h"

class GrGLConfigConversionEffect : public GrGLFragmentProcessor {
public:
    GrGLConfigConversionEffect(const GrProcessor& processor) {
        const GrConfigConversionEffect& configConversionEffect =
                processor.cast<GrConfigConversionEffect>();
        fSwapRedAndBlue = configConversionEffect.swapsRedAndBlue();
        fPMConversion = configConversionEffect.pmConversion();
    }

    virtual void emitCode(EmitArgs& args) override {
        // Using highp for GLES here in order to avoid some precision issues on specific GPUs.
        GrGLShaderVar tmpVar("tmpColor", kVec4f_GrSLType, 0, kHigh_GrSLPrecision);
        SkString tmpDecl;
        tmpVar.appendDecl(args.fBuilder->ctxInfo(), &tmpDecl);

        GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();

        fsBuilder->codeAppendf("%s;", tmpDecl.c_str());

        fsBuilder->codeAppendf("%s = ", tmpVar.c_str());
        fsBuilder->appendTextureLookup(args.fSamplers[0], args.fCoords[0].c_str(),
                                       args.fCoords[0].getType());
        fsBuilder->codeAppend(";");

        if (GrConfigConversionEffect::kNone_PMConversion == fPMConversion) {
            SkASSERT(fSwapRedAndBlue);
            fsBuilder->codeAppendf("%s = %s.bgra;", args.fOutputColor, tmpVar.c_str());
        } else {
            const char* swiz = fSwapRedAndBlue ? "bgr" : "rgb";
            switch (fPMConversion) {
                case GrConfigConversionEffect::kMulByAlpha_RoundUp_PMConversion:
                    fsBuilder->codeAppendf(
                        "%s = vec4(ceil(%s.%s * %s.a * 255.0) / 255.0, %s.a);",
                        tmpVar.c_str(), tmpVar.c_str(), swiz, tmpVar.c_str(), tmpVar.c_str());
                    break;
                case GrConfigConversionEffect::kMulByAlpha_RoundDown_PMConversion:
                    // Add a compensation(0.001) here to avoid the side effect of the floor operation.
                    // In Intel GPUs, the integer value converted from floor(%s.r * 255.0) / 255.0
                    // is less than the integer value converted from  %s.r by 1 when the %s.r is
                    // converted from the integer value 2^n, such as 1, 2, 4, 8, etc.
                    fsBuilder->codeAppendf(
                        "%s = vec4(floor(%s.%s * %s.a * 255.0 + 0.001) / 255.0, %s.a);",
                        tmpVar.c_str(), tmpVar.c_str(), swiz, tmpVar.c_str(), tmpVar.c_str());
                    break;
                case GrConfigConversionEffect::kDivByAlpha_RoundUp_PMConversion:
                    fsBuilder->codeAppendf(
                        "%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(ceil(%s.%s / %s.a * 255.0) / 255.0, %s.a);",
                        tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), swiz, tmpVar.c_str(), tmpVar.c_str());
                    break;
                case GrConfigConversionEffect::kDivByAlpha_RoundDown_PMConversion:
                    fsBuilder->codeAppendf(
                        "%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(floor(%s.%s / %s.a * 255.0) / 255.0, %s.a);",
                        tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), swiz, tmpVar.c_str(), tmpVar.c_str());
                    break;
                default:
                    SkFAIL("Unknown conversion op.");
                    break;
            }
            fsBuilder->codeAppendf("%s = %s;", args.fOutputColor, tmpVar.c_str());
        }
        SkString modulate;
        GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor);
        fsBuilder->codeAppend(modulate.c_str());
    }

    static inline void GenKey(const GrProcessor& processor, const GrGLSLCaps&,
                              GrProcessorKeyBuilder* b) {
        const GrConfigConversionEffect& conv = processor.cast<GrConfigConversionEffect>();
        uint32_t key = (conv.swapsRedAndBlue() ? 0 : 1) | (conv.pmConversion() << 1);
        b->add32(key);
    }

private:
    bool                                    fSwapRedAndBlue;
    GrConfigConversionEffect::PMConversion  fPMConversion;

    typedef GrGLFragmentProcessor INHERITED;

};

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

GrConfigConversionEffect::GrConfigConversionEffect(GrProcessorDataManager* procDataManager,
                                                   GrTexture* texture,
                                                   bool swapRedAndBlue,
                                                   PMConversion pmConversion,
                                                   const SkMatrix& matrix)
    : INHERITED(procDataManager, texture, matrix)
    , fSwapRedAndBlue(swapRedAndBlue)
    , fPMConversion(pmConversion) {
    this->initClassID<GrConfigConversionEffect>();
    SkASSERT(kRGBA_8888_GrPixelConfig == texture->config() ||
             kBGRA_8888_GrPixelConfig == texture->config());
    // Why did we pollute our texture cache instead of using a GrSingleTextureEffect?
    SkASSERT(swapRedAndBlue || kNone_PMConversion != pmConversion);
}

bool GrConfigConversionEffect::onIsEqual(const GrFragmentProcessor& s) const {
    const GrConfigConversionEffect& other = s.cast<GrConfigConversionEffect>();
    return other.fSwapRedAndBlue == fSwapRedAndBlue &&
           other.fPMConversion == fPMConversion;
}

void GrConfigConversionEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
    this->updateInvariantOutputForModulation(inout);
}

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

GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrConfigConversionEffect);

GrFragmentProcessor* GrConfigConversionEffect::TestCreate(GrProcessorTestData* d) {
    PMConversion pmConv = static_cast<PMConversion>(d->fRandom->nextULessThan(kPMConversionCnt));
    bool swapRB;
    if (kNone_PMConversion == pmConv) {
        swapRB = true;
    } else {
        swapRB = d->fRandom->nextBool();
    }
    return SkNEW_ARGS(GrConfigConversionEffect,
                                      (d->fProcDataManager,
                                       d->fTextures[GrProcessorUnitTest::kSkiaPMTextureIdx],
                                       swapRB,
                                       pmConv,
                                       GrTest::TestMatrix(d->fRandom)));
}

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

void GrConfigConversionEffect::getGLProcessorKey(const GrGLSLCaps& caps,
                                                 GrProcessorKeyBuilder* b) const {
    GrGLConfigConversionEffect::GenKey(*this, caps, b);
}

GrGLFragmentProcessor* GrConfigConversionEffect::createGLInstance() const {
    return SkNEW_ARGS(GrGLConfigConversionEffect, (*this));
}

void GrConfigConversionEffect::TestForPreservingPMConversions(GrContext* context,
                                                              PMConversion* pmToUPMRule,
                                                              PMConversion* upmToPMRule) {
    *pmToUPMRule = kNone_PMConversion;
    *upmToPMRule = kNone_PMConversion;
    SkAutoTMalloc<uint32_t> data(256 * 256 * 3);
    uint32_t* srcData = data.get();
    uint32_t* firstRead = data.get() + 256 * 256;
    uint32_t* secondRead = data.get() + 2 * 256 * 256;

    // Fill with every possible premultiplied A, color channel value. There will be 256-y duplicate
    // values in row y. We set r,g, and b to the same value since they are handled identically.
    for (int y = 0; y < 256; ++y) {
        for (int x = 0; x < 256; ++x) {
            uint8_t* color = reinterpret_cast<uint8_t*>(&srcData[256*y + x]);
            color[3] = y;
            color[2] = SkTMin(x, y);
            color[1] = SkTMin(x, y);
            color[0] = SkTMin(x, y);
        }
    }

    GrSurfaceDesc desc;
    desc.fFlags = kRenderTarget_GrSurfaceFlag;
    desc.fWidth = 256;
    desc.fHeight = 256;
    desc.fConfig = kRGBA_8888_GrPixelConfig;

    SkAutoTUnref<GrTexture> readTex(context->textureProvider()->createTexture(desc, true, NULL, 0));
    if (!readTex.get()) {
        return;
    }
    SkAutoTUnref<GrTexture> tempTex(context->textureProvider()->createTexture(desc, true, NULL, 0));
    if (!tempTex.get()) {
        return;
    }
    desc.fFlags = kNone_GrSurfaceFlags;
    SkAutoTUnref<GrTexture> dataTex(context->textureProvider()->createTexture(desc, true, data, 0));
    if (!dataTex.get()) {
        return;
    }

    static const PMConversion kConversionRules[][2] = {
        {kDivByAlpha_RoundDown_PMConversion, kMulByAlpha_RoundUp_PMConversion},
        {kDivByAlpha_RoundUp_PMConversion, kMulByAlpha_RoundDown_PMConversion},
    };

    bool failed = true;

    for (size_t i = 0; i < SK_ARRAY_COUNT(kConversionRules) && failed; ++i) {
        *pmToUPMRule = kConversionRules[i][0];
        *upmToPMRule = kConversionRules[i][1];

        static const SkRect kDstRect = SkRect::MakeWH(SkIntToScalar(256), SkIntToScalar(256));
        static const SkRect kSrcRect = SkRect::MakeWH(SK_Scalar1, SK_Scalar1);
        // We do a PM->UPM draw from dataTex to readTex and read the data. Then we do a UPM->PM draw
        // from readTex to tempTex followed by a PM->UPM draw to readTex and finally read the data.
        // We then verify that two reads produced the same values.

        GrPaint paint1;
        GrPaint paint2;
        GrPaint paint3;
        SkAutoTUnref<GrFragmentProcessor> pmToUPM1(
                SkNEW_ARGS(GrConfigConversionEffect,
                           (paint1.getProcessorDataManager(), dataTex, false, *pmToUPMRule,
                            SkMatrix::I())));
        SkAutoTUnref<GrFragmentProcessor> upmToPM(
                SkNEW_ARGS(GrConfigConversionEffect,
                           (paint2.getProcessorDataManager(), readTex, false, *upmToPMRule,
                            SkMatrix::I())));
        SkAutoTUnref<GrFragmentProcessor> pmToUPM2(
                SkNEW_ARGS(GrConfigConversionEffect,
                           (paint3.getProcessorDataManager(), tempTex, false, *pmToUPMRule,
                            SkMatrix::I())));

        paint1.addColorProcessor(pmToUPM1);

        GrDrawContext* readDrawContext = context->drawContext();
        if (!readDrawContext) {
            failed = true;
            break;
        }

        readDrawContext->drawNonAARectToRect(readTex->asRenderTarget(),
                                             GrClip::WideOpen(),
                                             paint1,
                                             SkMatrix::I(),
                                             kDstRect,
                                             kSrcRect);

        readTex->readPixels(0, 0, 256, 256, kRGBA_8888_GrPixelConfig, firstRead);

        paint2.addColorProcessor(upmToPM);

        GrDrawContext* tempDrawContext = context->drawContext();
        if (!tempDrawContext) {
            failed = true;
            break;
        }
        tempDrawContext->drawNonAARectToRect(tempTex->asRenderTarget(),
                                             GrClip::WideOpen(),
                                             paint2,
                                             SkMatrix::I(),
                                             kDstRect,
                                             kSrcRect);

        paint3.addColorProcessor(pmToUPM2);

        readDrawContext = context->drawContext();
        if (!readDrawContext) {
            failed = true;
            break;
        }

        readDrawContext->drawNonAARectToRect(readTex->asRenderTarget(),
                                             GrClip::WideOpen(),
                                             paint3,
                                             SkMatrix::I(),
                                             kDstRect,
                                             kSrcRect);

        readTex->readPixels(0, 0, 256, 256, kRGBA_8888_GrPixelConfig, secondRead);

        failed = false;
        for (int y = 0; y < 256 && !failed; ++y) {
            for (int x = 0; x <= y; ++x) {
                if (firstRead[256 * y + x] != secondRead[256 * y + x]) {
                    failed = true;
                    break;
                }
            }
        }
    }
    if (failed) {
        *pmToUPMRule = kNone_PMConversion;
        *upmToPMRule = kNone_PMConversion;
    }
}

const GrFragmentProcessor* GrConfigConversionEffect::Create(GrProcessorDataManager* procDataManager,
                                                            GrTexture* texture,
                                                            bool swapRedAndBlue,
                                                            PMConversion pmConversion,
                                                            const SkMatrix& matrix) {
    if (!swapRedAndBlue && kNone_PMConversion == pmConversion) {
        // If we returned a GrConfigConversionEffect that was equivalent to a GrSimpleTextureEffect
        // then we may pollute our texture cache with redundant shaders. So in the case that no
        // conversions were requested we instead return a GrSimpleTextureEffect.
        return GrSimpleTextureEffect::Create(procDataManager, texture, matrix);
    } else {
        if (kRGBA_8888_GrPixelConfig != texture->config() &&
            kBGRA_8888_GrPixelConfig != texture->config() &&
            kNone_PMConversion != pmConversion) {
            // The PM conversions assume colors are 0..255
            return NULL;
        }
        return SkNEW_ARGS(GrConfigConversionEffect, (procDataManager,
                                                     texture,
                                                     swapRedAndBlue,
                                                     pmConversion,
                                                     matrix));
    }
}
<commit_msg>Update assert to allow config conversion effect for all configs when not premul/unpremuling<commit_after>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrConfigConversionEffect.h"
#include "GrContext.h"
#include "GrDrawContext.h"
#include "GrInvariantOutput.h"
#include "GrSimpleTextureEffect.h"
#include "SkMatrix.h"
#include "gl/GrGLFragmentProcessor.h"
#include "gl/builders/GrGLProgramBuilder.h"

class GrGLConfigConversionEffect : public GrGLFragmentProcessor {
public:
    GrGLConfigConversionEffect(const GrProcessor& processor) {
        const GrConfigConversionEffect& configConversionEffect =
                processor.cast<GrConfigConversionEffect>();
        fSwapRedAndBlue = configConversionEffect.swapsRedAndBlue();
        fPMConversion = configConversionEffect.pmConversion();
    }

    virtual void emitCode(EmitArgs& args) override {
        // Using highp for GLES here in order to avoid some precision issues on specific GPUs.
        GrGLShaderVar tmpVar("tmpColor", kVec4f_GrSLType, 0, kHigh_GrSLPrecision);
        SkString tmpDecl;
        tmpVar.appendDecl(args.fBuilder->ctxInfo(), &tmpDecl);

        GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();

        fsBuilder->codeAppendf("%s;", tmpDecl.c_str());

        fsBuilder->codeAppendf("%s = ", tmpVar.c_str());
        fsBuilder->appendTextureLookup(args.fSamplers[0], args.fCoords[0].c_str(),
                                       args.fCoords[0].getType());
        fsBuilder->codeAppend(";");

        if (GrConfigConversionEffect::kNone_PMConversion == fPMConversion) {
            SkASSERT(fSwapRedAndBlue);
            fsBuilder->codeAppendf("%s = %s.bgra;", args.fOutputColor, tmpVar.c_str());
        } else {
            const char* swiz = fSwapRedAndBlue ? "bgr" : "rgb";
            switch (fPMConversion) {
                case GrConfigConversionEffect::kMulByAlpha_RoundUp_PMConversion:
                    fsBuilder->codeAppendf(
                        "%s = vec4(ceil(%s.%s * %s.a * 255.0) / 255.0, %s.a);",
                        tmpVar.c_str(), tmpVar.c_str(), swiz, tmpVar.c_str(), tmpVar.c_str());
                    break;
                case GrConfigConversionEffect::kMulByAlpha_RoundDown_PMConversion:
                    // Add a compensation(0.001) here to avoid the side effect of the floor operation.
                    // In Intel GPUs, the integer value converted from floor(%s.r * 255.0) / 255.0
                    // is less than the integer value converted from  %s.r by 1 when the %s.r is
                    // converted from the integer value 2^n, such as 1, 2, 4, 8, etc.
                    fsBuilder->codeAppendf(
                        "%s = vec4(floor(%s.%s * %s.a * 255.0 + 0.001) / 255.0, %s.a);",
                        tmpVar.c_str(), tmpVar.c_str(), swiz, tmpVar.c_str(), tmpVar.c_str());
                    break;
                case GrConfigConversionEffect::kDivByAlpha_RoundUp_PMConversion:
                    fsBuilder->codeAppendf(
                        "%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(ceil(%s.%s / %s.a * 255.0) / 255.0, %s.a);",
                        tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), swiz, tmpVar.c_str(), tmpVar.c_str());
                    break;
                case GrConfigConversionEffect::kDivByAlpha_RoundDown_PMConversion:
                    fsBuilder->codeAppendf(
                        "%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(floor(%s.%s / %s.a * 255.0) / 255.0, %s.a);",
                        tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), swiz, tmpVar.c_str(), tmpVar.c_str());
                    break;
                default:
                    SkFAIL("Unknown conversion op.");
                    break;
            }
            fsBuilder->codeAppendf("%s = %s;", args.fOutputColor, tmpVar.c_str());
        }
        SkString modulate;
        GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor);
        fsBuilder->codeAppend(modulate.c_str());
    }

    static inline void GenKey(const GrProcessor& processor, const GrGLSLCaps&,
                              GrProcessorKeyBuilder* b) {
        const GrConfigConversionEffect& conv = processor.cast<GrConfigConversionEffect>();
        uint32_t key = (conv.swapsRedAndBlue() ? 0 : 1) | (conv.pmConversion() << 1);
        b->add32(key);
    }

private:
    bool                                    fSwapRedAndBlue;
    GrConfigConversionEffect::PMConversion  fPMConversion;

    typedef GrGLFragmentProcessor INHERITED;

};

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

GrConfigConversionEffect::GrConfigConversionEffect(GrProcessorDataManager* procDataManager,
                                                   GrTexture* texture,
                                                   bool swapRedAndBlue,
                                                   PMConversion pmConversion,
                                                   const SkMatrix& matrix)
    : INHERITED(procDataManager, texture, matrix)
    , fSwapRedAndBlue(swapRedAndBlue)
    , fPMConversion(pmConversion) {
    this->initClassID<GrConfigConversionEffect>();
    // We expect to get here with non-BGRA/RGBA only if we're doing not doing a premul/unpremul
    // conversion.
    SkASSERT((kRGBA_8888_GrPixelConfig == texture->config() ||
              kBGRA_8888_GrPixelConfig == texture->config()) ||
              kNone_PMConversion == pmConversion);
    // Why did we pollute our texture cache instead of using a GrSingleTextureEffect?
    SkASSERT(swapRedAndBlue || kNone_PMConversion != pmConversion);
}

bool GrConfigConversionEffect::onIsEqual(const GrFragmentProcessor& s) const {
    const GrConfigConversionEffect& other = s.cast<GrConfigConversionEffect>();
    return other.fSwapRedAndBlue == fSwapRedAndBlue &&
           other.fPMConversion == fPMConversion;
}

void GrConfigConversionEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
    this->updateInvariantOutputForModulation(inout);
}

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

GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrConfigConversionEffect);

GrFragmentProcessor* GrConfigConversionEffect::TestCreate(GrProcessorTestData* d) {
    PMConversion pmConv = static_cast<PMConversion>(d->fRandom->nextULessThan(kPMConversionCnt));
    bool swapRB;
    if (kNone_PMConversion == pmConv) {
        swapRB = true;
    } else {
        swapRB = d->fRandom->nextBool();
    }
    return SkNEW_ARGS(GrConfigConversionEffect,
                                      (d->fProcDataManager,
                                       d->fTextures[GrProcessorUnitTest::kSkiaPMTextureIdx],
                                       swapRB,
                                       pmConv,
                                       GrTest::TestMatrix(d->fRandom)));
}

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

void GrConfigConversionEffect::getGLProcessorKey(const GrGLSLCaps& caps,
                                                 GrProcessorKeyBuilder* b) const {
    GrGLConfigConversionEffect::GenKey(*this, caps, b);
}

GrGLFragmentProcessor* GrConfigConversionEffect::createGLInstance() const {
    return SkNEW_ARGS(GrGLConfigConversionEffect, (*this));
}

void GrConfigConversionEffect::TestForPreservingPMConversions(GrContext* context,
                                                              PMConversion* pmToUPMRule,
                                                              PMConversion* upmToPMRule) {
    *pmToUPMRule = kNone_PMConversion;
    *upmToPMRule = kNone_PMConversion;
    SkAutoTMalloc<uint32_t> data(256 * 256 * 3);
    uint32_t* srcData = data.get();
    uint32_t* firstRead = data.get() + 256 * 256;
    uint32_t* secondRead = data.get() + 2 * 256 * 256;

    // Fill with every possible premultiplied A, color channel value. There will be 256-y duplicate
    // values in row y. We set r,g, and b to the same value since they are handled identically.
    for (int y = 0; y < 256; ++y) {
        for (int x = 0; x < 256; ++x) {
            uint8_t* color = reinterpret_cast<uint8_t*>(&srcData[256*y + x]);
            color[3] = y;
            color[2] = SkTMin(x, y);
            color[1] = SkTMin(x, y);
            color[0] = SkTMin(x, y);
        }
    }

    GrSurfaceDesc desc;
    desc.fFlags = kRenderTarget_GrSurfaceFlag;
    desc.fWidth = 256;
    desc.fHeight = 256;
    desc.fConfig = kRGBA_8888_GrPixelConfig;

    SkAutoTUnref<GrTexture> readTex(context->textureProvider()->createTexture(desc, true, NULL, 0));
    if (!readTex.get()) {
        return;
    }
    SkAutoTUnref<GrTexture> tempTex(context->textureProvider()->createTexture(desc, true, NULL, 0));
    if (!tempTex.get()) {
        return;
    }
    desc.fFlags = kNone_GrSurfaceFlags;
    SkAutoTUnref<GrTexture> dataTex(context->textureProvider()->createTexture(desc, true, data, 0));
    if (!dataTex.get()) {
        return;
    }

    static const PMConversion kConversionRules[][2] = {
        {kDivByAlpha_RoundDown_PMConversion, kMulByAlpha_RoundUp_PMConversion},
        {kDivByAlpha_RoundUp_PMConversion, kMulByAlpha_RoundDown_PMConversion},
    };

    bool failed = true;

    for (size_t i = 0; i < SK_ARRAY_COUNT(kConversionRules) && failed; ++i) {
        *pmToUPMRule = kConversionRules[i][0];
        *upmToPMRule = kConversionRules[i][1];

        static const SkRect kDstRect = SkRect::MakeWH(SkIntToScalar(256), SkIntToScalar(256));
        static const SkRect kSrcRect = SkRect::MakeWH(SK_Scalar1, SK_Scalar1);
        // We do a PM->UPM draw from dataTex to readTex and read the data. Then we do a UPM->PM draw
        // from readTex to tempTex followed by a PM->UPM draw to readTex and finally read the data.
        // We then verify that two reads produced the same values.

        GrPaint paint1;
        GrPaint paint2;
        GrPaint paint3;
        SkAutoTUnref<GrFragmentProcessor> pmToUPM1(
                SkNEW_ARGS(GrConfigConversionEffect,
                           (paint1.getProcessorDataManager(), dataTex, false, *pmToUPMRule,
                            SkMatrix::I())));
        SkAutoTUnref<GrFragmentProcessor> upmToPM(
                SkNEW_ARGS(GrConfigConversionEffect,
                           (paint2.getProcessorDataManager(), readTex, false, *upmToPMRule,
                            SkMatrix::I())));
        SkAutoTUnref<GrFragmentProcessor> pmToUPM2(
                SkNEW_ARGS(GrConfigConversionEffect,
                           (paint3.getProcessorDataManager(), tempTex, false, *pmToUPMRule,
                            SkMatrix::I())));

        paint1.addColorProcessor(pmToUPM1);

        GrDrawContext* readDrawContext = context->drawContext();
        if (!readDrawContext) {
            failed = true;
            break;
        }

        readDrawContext->drawNonAARectToRect(readTex->asRenderTarget(),
                                             GrClip::WideOpen(),
                                             paint1,
                                             SkMatrix::I(),
                                             kDstRect,
                                             kSrcRect);

        readTex->readPixels(0, 0, 256, 256, kRGBA_8888_GrPixelConfig, firstRead);

        paint2.addColorProcessor(upmToPM);

        GrDrawContext* tempDrawContext = context->drawContext();
        if (!tempDrawContext) {
            failed = true;
            break;
        }
        tempDrawContext->drawNonAARectToRect(tempTex->asRenderTarget(),
                                             GrClip::WideOpen(),
                                             paint2,
                                             SkMatrix::I(),
                                             kDstRect,
                                             kSrcRect);

        paint3.addColorProcessor(pmToUPM2);

        readDrawContext = context->drawContext();
        if (!readDrawContext) {
            failed = true;
            break;
        }

        readDrawContext->drawNonAARectToRect(readTex->asRenderTarget(),
                                             GrClip::WideOpen(),
                                             paint3,
                                             SkMatrix::I(),
                                             kDstRect,
                                             kSrcRect);

        readTex->readPixels(0, 0, 256, 256, kRGBA_8888_GrPixelConfig, secondRead);

        failed = false;
        for (int y = 0; y < 256 && !failed; ++y) {
            for (int x = 0; x <= y; ++x) {
                if (firstRead[256 * y + x] != secondRead[256 * y + x]) {
                    failed = true;
                    break;
                }
            }
        }
    }
    if (failed) {
        *pmToUPMRule = kNone_PMConversion;
        *upmToPMRule = kNone_PMConversion;
    }
}

const GrFragmentProcessor* GrConfigConversionEffect::Create(GrProcessorDataManager* procDataManager,
                                                            GrTexture* texture,
                                                            bool swapRedAndBlue,
                                                            PMConversion pmConversion,
                                                            const SkMatrix& matrix) {
    if (!swapRedAndBlue && kNone_PMConversion == pmConversion) {
        // If we returned a GrConfigConversionEffect that was equivalent to a GrSimpleTextureEffect
        // then we may pollute our texture cache with redundant shaders. So in the case that no
        // conversions were requested we instead return a GrSimpleTextureEffect.
        return GrSimpleTextureEffect::Create(procDataManager, texture, matrix);
    } else {
        if (kRGBA_8888_GrPixelConfig != texture->config() &&
            kBGRA_8888_GrPixelConfig != texture->config() &&
            kNone_PMConversion != pmConversion) {
            // The PM conversions assume colors are 0..255
            return NULL;
        }
        return SkNEW_ARGS(GrConfigConversionEffect, (procDataManager,
                                                     texture,
                                                     swapRedAndBlue,
                                                     pmConversion,
                                                     matrix));
    }
}
<|endoftext|>


<commit_before>#include "iteration/group/group_solve_iteration.h"

namespace bart {

namespace iteration {

namespace group {

template <int dim>
GroupSolveIteration<dim>::GroupSolveIteration(
    std::unique_ptr<GroupSolver> group_solver_ptr,
    std::unique_ptr<ConvergenceChecker> convergence_checker_ptr,
    std::unique_ptr<MomentCalculator> moment_calculator_ptr,
    const std::shared_ptr<GroupSolution> &group_solution_ptr,
    const std::shared_ptr<Reporter> &reporter_ptr)
    : group_solver_ptr_(std::move(group_solver_ptr)),
      convergence_checker_ptr_(std::move(convergence_checker_ptr)),
      moment_calculator_ptr_(std::move(moment_calculator_ptr)),
      group_solution_ptr_(group_solution_ptr),
      reporter_ptr_(reporter_ptr) {

  AssertThrow(group_solver_ptr_ != nullptr,
              dealii::ExcMessage("Group solver pointer passed to "
                                 "GroupSolveIteration constructor is null"));
  AssertThrow(convergence_checker_ptr_ != nullptr,
              dealii::ExcMessage("Convergence checker pointer passed to "
                                 "GroupSolveIteration constructor is null"));
  AssertThrow(moment_calculator_ptr_ != nullptr,
              dealii::ExcMessage("Moment calculator pointer passed to "
                                 "GroupSolveIteration constructor is null"));
  AssertThrow(group_solution_ptr_ != nullptr,
              dealii::ExcMessage("Group solution pointer passed to "
                                 "GroupSolveIteration constructor is null"));
}

template<int dim>
void GroupSolveIteration<dim>::Iterate(system::System &system) {

  const int total_groups = system.total_groups;
  const int total_angles = system.total_angles;
  system::moments::MomentVector current_scalar_flux, previous_scalar_flux;

  if (reporter_ptr_ != nullptr)
    reporter_ptr_->Report("..Inner group iteration\n");

  for (int group = 0; group < total_groups; ++group) {
    PerformPerGroup(system, group);

    convergence::Status convergence_status;
    convergence_checker_ptr_->Reset();
    do {

      if (!convergence_status.is_complete) {
        for (int angle = 0; angle < total_angles; ++angle)
          UpdateSystem(system, group, angle);
      }

      previous_scalar_flux = current_scalar_flux;

      SolveGroup(group, system);

      current_scalar_flux = GetScalarFlux(group, system);

      if (convergence_status.iteration_number == 0) {
        previous_scalar_flux = current_scalar_flux;
        previous_scalar_flux = 0;
      }

      convergence_status = CheckConvergence(current_scalar_flux,
                                            previous_scalar_flux);

      if (reporter_ptr_ != nullptr)
        reporter_ptr_->Report(convergence_status);

    } while (!convergence_status.is_complete);
    UpdateCurrentMoments(system, group);
    if (is_storing_angular_solution_)
      StoreAngularSolution(system, group);
  }
}

template <int dim>
void GroupSolveIteration<dim>::SolveGroup(int group, system::System &system) {
  group_solver_ptr_->SolveGroup(group, system, *group_solution_ptr_);
}

template <int dim>
system::moments::MomentVector GroupSolveIteration<dim>::GetScalarFlux(
    const int group, system::System &) {
  return moment_calculator_ptr_->CalculateMoment(group_solution_ptr_.get(),
                                                 group, 0, 0);
}

template <int dim>
convergence::Status GroupSolveIteration<dim>::CheckConvergence(
    system::moments::MomentVector &current_iteration,
    system::moments::MomentVector &previous_iteration) {
  return convergence_checker_ptr_->CheckFinalConvergence(current_iteration,
                                                         previous_iteration);
}

template <int dim>
void GroupSolveIteration<dim>::UpdateCurrentMoments(system::System &system,
                                                    const int group) {
  auto& current_moments = *system.current_moments;
  const int max_harmonic_l = current_moments.max_harmonic_l();

  for (int l = 0; l <= max_harmonic_l; ++l) {
    for (int m = -l; m <= l; ++m) {
      current_moments[{group, l, m}] = moment_calculator_ptr_->CalculateMoment(
          group_solution_ptr_.get(), group, l, m);
    }
  }
}

template<int dim>
void GroupSolveIteration<dim>::PerformPerGroup(system::System &/*system*/,
                                               const int group) {
  if (reporter_ptr_ != nullptr) {
    std::string report{"....Group: "};
    report += std::to_string(group);
    report += "\n";
    reporter_ptr_->Report(report);
  }
}
template<int dim>
void GroupSolveIteration<dim>::StoreAngularSolution(system::System& system,
                                                    const int group) {
  for (int angle = 0; angle < system.total_angles; ++angle) {
    auto& stored_solution = angular_solution_ptr_map_.at(
        system::SolutionIndex(group, angle));
    auto& current_solution = group_solution_ptr_->GetSolution(angle);
    *stored_solution = current_solution;
  }
}

template class GroupSolveIteration<1>;
template class GroupSolveIteration<2>;
template class GroupSolveIteration<3>;

} // namespace group

} // namespace iteration

} // namespace bart
<commit_msg>fixed current moments update location in GroupSolveIteration<commit_after>#include "iteration/group/group_solve_iteration.h"

namespace bart {

namespace iteration {

namespace group {

template <int dim>
GroupSolveIteration<dim>::GroupSolveIteration(
    std::unique_ptr<GroupSolver> group_solver_ptr,
    std::unique_ptr<ConvergenceChecker> convergence_checker_ptr,
    std::unique_ptr<MomentCalculator> moment_calculator_ptr,
    const std::shared_ptr<GroupSolution> &group_solution_ptr,
    const std::shared_ptr<Reporter> &reporter_ptr)
    : group_solver_ptr_(std::move(group_solver_ptr)),
      convergence_checker_ptr_(std::move(convergence_checker_ptr)),
      moment_calculator_ptr_(std::move(moment_calculator_ptr)),
      group_solution_ptr_(group_solution_ptr),
      reporter_ptr_(reporter_ptr) {

  AssertThrow(group_solver_ptr_ != nullptr,
              dealii::ExcMessage("Group solver pointer passed to "
                                 "GroupSolveIteration constructor is null"));
  AssertThrow(convergence_checker_ptr_ != nullptr,
              dealii::ExcMessage("Convergence checker pointer passed to "
                                 "GroupSolveIteration constructor is null"));
  AssertThrow(moment_calculator_ptr_ != nullptr,
              dealii::ExcMessage("Moment calculator pointer passed to "
                                 "GroupSolveIteration constructor is null"));
  AssertThrow(group_solution_ptr_ != nullptr,
              dealii::ExcMessage("Group solution pointer passed to "
                                 "GroupSolveIteration constructor is null"));
}

template<int dim>
void GroupSolveIteration<dim>::Iterate(system::System &system) {

  const int total_groups = system.total_groups;
  const int total_angles = system.total_angles;
  system::moments::MomentVector current_scalar_flux, previous_scalar_flux;

  if (reporter_ptr_ != nullptr)
    reporter_ptr_->Report("..Inner group iteration\n");

  for (int group = 0; group < total_groups; ++group) {
    PerformPerGroup(system, group);

    convergence::Status convergence_status;
    convergence_checker_ptr_->Reset();
    do {
      if (!convergence_status.is_complete) {
        for (int angle = 0; angle < total_angles; ++angle)
          UpdateSystem(system, group, angle);
      }

      previous_scalar_flux = current_scalar_flux;

      SolveGroup(group, system);

      current_scalar_flux = GetScalarFlux(group, system);

      if (convergence_status.iteration_number == 0) {
        previous_scalar_flux = current_scalar_flux;
        previous_scalar_flux = 0;
      }
//      std::cout << "Current scalar flux: ";
//      current_scalar_flux.print(std::cout);
//      std::cout << "Previous scalar flux: ";
//      previous_scalar_flux.print(std::cout);

      convergence_status = CheckConvergence(current_scalar_flux,
                                            previous_scalar_flux);

      if (reporter_ptr_ != nullptr)
        reporter_ptr_->Report(convergence_status);
      UpdateCurrentMoments(system, group);
    } while (!convergence_status.is_complete);

    if (is_storing_angular_solution_)
      StoreAngularSolution(system, group);
  }
}

template <int dim>
void GroupSolveIteration<dim>::SolveGroup(int group, system::System &system) {
  group_solver_ptr_->SolveGroup(group, system, *group_solution_ptr_);
}

template <int dim>
system::moments::MomentVector GroupSolveIteration<dim>::GetScalarFlux(
    const int group, system::System &) {
  return moment_calculator_ptr_->CalculateMoment(group_solution_ptr_.get(),
                                                 group, 0, 0);
}

template <int dim>
convergence::Status GroupSolveIteration<dim>::CheckConvergence(
    system::moments::MomentVector &current_iteration,
    system::moments::MomentVector &previous_iteration) {
  return convergence_checker_ptr_->CheckFinalConvergence(current_iteration,
                                                         previous_iteration);
}

template <int dim>
void GroupSolveIteration<dim>::UpdateCurrentMoments(system::System &system,
                                                    const int group) {
  auto& current_moments = *system.current_moments;
  const int max_harmonic_l = current_moments.max_harmonic_l();

  for (int l = 0; l <= max_harmonic_l; ++l) {
    for (int m = -l; m <= l; ++m) {
      current_moments[{group, l, m}] = moment_calculator_ptr_->CalculateMoment(
          group_solution_ptr_.get(), group, l, m);
    }
  }
}

template<int dim>
void GroupSolveIteration<dim>::PerformPerGroup(system::System &/*system*/,
                                               const int group) {
  if (reporter_ptr_ != nullptr) {
    std::string report{"....Group: "};
    report += std::to_string(group);
    report += "\n";
    reporter_ptr_->Report(report);
  }
}
template<int dim>
void GroupSolveIteration<dim>::StoreAngularSolution(system::System& system,
                                                    const int group) {
  for (int angle = 0; angle < system.total_angles; ++angle) {
    auto& stored_solution = angular_solution_ptr_map_.at(
        system::SolutionIndex(group, angle));
    auto& current_solution = group_solution_ptr_->GetSolution(angle);
    *stored_solution = current_solution;
  }
}

template class GroupSolveIteration<1>;
template class GroupSolveIteration<2>;
template class GroupSolveIteration<3>;

} // namespace group

} // namespace iteration

} // namespace bart
<|endoftext|>


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

#include "flutter/shell/common/rasterizer.h"

#include <utility>

#include "third_party/skia/include/core/SkEncodedImageFormat.h"
#include "third_party/skia/include/core/SkImageEncoder.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/core/SkSurfaceCharacterization.h"
#include "third_party/skia/include/utils/SkBase64.h"

#ifdef ERROR
#undef ERROR
#endif

namespace shell {

Rasterizer::Rasterizer(blink::TaskRunners task_runners)
    : Rasterizer(std::move(task_runners),
                 std::make_unique<flow::CompositorContext>()) {}

Rasterizer::Rasterizer(
    blink::TaskRunners task_runners,
    std::unique_ptr<flow::CompositorContext> compositor_context)
    : task_runners_(std::move(task_runners)),
      compositor_context_(std::move(compositor_context)),
      weak_factory_(this) {
  FML_DCHECK(compositor_context_);
}

Rasterizer::~Rasterizer() = default;

fml::WeakPtr<Rasterizer> Rasterizer::GetWeakPtr() const {
  return weak_factory_.GetWeakPtr();
}

void Rasterizer::Setup(std::unique_ptr<Surface> surface) {
  surface_ = std::move(surface);
  compositor_context_->OnGrContextCreated();
}

void Rasterizer::Teardown() {
  compositor_context_->OnGrContextDestroyed();
  surface_.reset();
  last_layer_tree_.reset();
}

flow::TextureRegistry* Rasterizer::GetTextureRegistry() {
  return &compositor_context_->texture_registry();
}

flow::LayerTree* Rasterizer::GetLastLayerTree() {
  return last_layer_tree_.get();
}

void Rasterizer::DrawLastLayerTree() {
  if (!last_layer_tree_ || !surface_) {
    return;
  }
  DrawToSurface(*last_layer_tree_);
}

void Rasterizer::Draw(
    fml::RefPtr<flutter::Pipeline<flow::LayerTree>> pipeline) {
  TRACE_EVENT0("flutter", "GPURasterizer::Draw");

  flutter::Pipeline<flow::LayerTree>::Consumer consumer =
      std::bind(&Rasterizer::DoDraw, this, std::placeholders::_1);

  // Consume as many pipeline items as possible. But yield the event loop
  // between successive tries.
  switch (pipeline->Consume(consumer)) {
    case flutter::PipelineConsumeResult::MoreAvailable: {
      task_runners_.GetGPUTaskRunner()->PostTask(
          [weak_this = weak_factory_.GetWeakPtr(), pipeline]() {
            if (weak_this) {
              weak_this->Draw(pipeline);
            }
          });
      break;
    }
    default:
      break;
  }
}

void Rasterizer::DoDraw(std::unique_ptr<flow::LayerTree> layer_tree) {
  if (!layer_tree || !surface_) {
    return;
  }

  if (DrawToSurface(*layer_tree)) {
    last_layer_tree_ = std::move(layer_tree);
  }
}

bool Rasterizer::DrawToSurface(flow::LayerTree& layer_tree) {
  FML_DCHECK(surface_);

  auto frame = surface_->AcquireFrame(layer_tree.frame_size());

  if (frame == nullptr) {
    return false;
  }

  // There is no way for the compositor to know how long the layer tree
  // construction took. Fortunately, the layer tree does. Grab that time
  // for instrumentation.
  compositor_context_->engine_time().SetLapTime(layer_tree.construction_time());

  auto canvas = frame->SkiaCanvas();

  auto compositor_frame = compositor_context_->AcquireFrame(
      surface_->GetContext(), canvas, surface_->GetRootTransformation(), true);

  if (canvas) {
    canvas->clear(SK_ColorTRANSPARENT);
  }

  if (compositor_frame && compositor_frame->Raster(layer_tree, false)) {
    frame->Submit();
    FireNextFrameCallbackIfPresent();
    return true;
  }

  return false;
}

static sk_sp<SkPicture> ScreenshotLayerTreeAsPicture(
    flow::LayerTree* tree,
    flow::CompositorContext& compositor_context) {
  FML_DCHECK(tree != nullptr);
  SkPictureRecorder recorder;
  recorder.beginRecording(
      SkRect::MakeWH(tree->frame_size().width(), tree->frame_size().height()));

  SkMatrix root_surface_transformation;
  root_surface_transformation.reset();

  auto frame =
      compositor_context.AcquireFrame(nullptr, recorder.getRecordingCanvas(),
                                      root_surface_transformation, false);

  frame->Raster(*tree, true);

  return recorder.finishRecordingAsPicture();
}

static sk_sp<SkSurface> CreateSnapshotSurface(GrContext* surface_context,
                                              const SkISize& size) {
  const auto image_info = SkImageInfo::MakeN32Premul(size);
  if (surface_context) {
    // There is a rendering surface that may contain textures that are going to
    // be referenced in the layer tree about to be drawn.
    return SkSurface::MakeRenderTarget(surface_context,  //
                                       SkBudgeted::kNo,  //
                                       image_info        //
    );
  }

  // There is no rendering surface, assume no GPU textures are present and
  // create a raster surface.
  return SkSurface::MakeRaster(image_info);
}

static sk_sp<SkData> ScreenshotLayerTreeAsImage(
    flow::LayerTree* tree,
    flow::CompositorContext& compositor_context,
    GrContext* surface_context,
    bool compressed) {
  // Attempt to create a snapshot surface depending on whether we have access to
  // a valid GPU rendering context.
  auto snapshot_surface =
      CreateSnapshotSurface(surface_context, tree->frame_size());
  if (snapshot_surface == nullptr) {
    FML_LOG(ERROR) << "Screenshot: unable to create snapshot surface";
    return nullptr;
  }

  // Draw the current layer tree into the snapshot surface.
  auto canvas = snapshot_surface->getCanvas();

  // There is no root surface transformation for the screenshot layer. Reset the
  // matrix to identity.
  SkMatrix root_surface_transformation;
  root_surface_transformation.reset();

  auto frame = compositor_context.AcquireFrame(
      surface_context, canvas, root_surface_transformation, false);
  canvas->clear(SK_ColorTRANSPARENT);
  frame->Raster(*tree, true);
  canvas->flush();

  // Prepare an image from the surface, this image may potentially be on th GPU.
  auto potentially_gpu_snapshot = snapshot_surface->makeImageSnapshot();
  if (!potentially_gpu_snapshot) {
    FML_LOG(ERROR) << "Screenshot: unable to make image screenshot";
    return nullptr;
  }

  // Copy the GPU image snapshot into CPU memory.
  auto cpu_snapshot = potentially_gpu_snapshot->makeRasterImage();
  if (!cpu_snapshot) {
    FML_LOG(ERROR) << "Screenshot: unable to make raster image";
    return nullptr;
  }

  // If the caller want the pixels to be compressed, there is a Skia utility to
  // compress to PNG. Use that.
  if (compressed) {
    return cpu_snapshot->encodeToData();
  }

  // Copy it into a bitmap and return the same.
  SkPixmap pixmap;
  if (!cpu_snapshot->peekPixels(&pixmap)) {
    FML_LOG(ERROR) << "Screenshot: unable to obtain bitmap pixels";
    return nullptr;
  }

  return SkData::MakeWithCopy(pixmap.addr32(), pixmap.computeByteSize());
}

Rasterizer::Screenshot Rasterizer::ScreenshotLastLayerTree(
    Rasterizer::ScreenshotType type,
    bool base64_encode) {
  auto layer_tree = GetLastLayerTree();
  if (layer_tree == nullptr) {
    FML_LOG(ERROR) << "Last layer tree was null when screenshotting.";
    return {};
  }

  sk_sp<SkData> data = nullptr;

  GrContext* surface_context = surface_ ? surface_->GetContext() : nullptr;

  switch (type) {
    case ScreenshotType::SkiaPicture:
      data = ScreenshotLayerTreeAsPicture(layer_tree, *compositor_context_)
                 ->serialize();
      break;
    case ScreenshotType::UncompressedImage:
      data = ScreenshotLayerTreeAsImage(layer_tree, *compositor_context_,
                                        surface_context, false);
      break;
    case ScreenshotType::CompressedImage:
      data = ScreenshotLayerTreeAsImage(layer_tree, *compositor_context_,
                                        surface_context, true);
      break;
  }

  if (data == nullptr) {
    FML_LOG(ERROR) << "Screenshot data was null.";
    return {};
  }

  if (base64_encode) {
    size_t b64_size = SkBase64::Encode(data->data(), data->size(), nullptr);
    auto b64_data = SkData::MakeUninitialized(b64_size);
    SkBase64::Encode(data->data(), data->size(), b64_data->writable_data());
    return Rasterizer::Screenshot{b64_data, layer_tree->frame_size()};
  }

  return Rasterizer::Screenshot{data, layer_tree->frame_size()};
}

void Rasterizer::SetNextFrameCallback(fml::closure callback) {
  next_frame_callback_ = callback;
}

void Rasterizer::FireNextFrameCallbackIfPresent() {
  if (!next_frame_callback_) {
    return;
  }
  // It is safe for the callback to set a new callback.
  auto callback = next_frame_callback_;
  next_frame_callback_ = nullptr;
  callback();
}

}  // namespace shell
<commit_msg>Always serialize fonts during skp capturing (#6160)<commit_after>// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/shell/common/rasterizer.h"

#include <utility>

#include "third_party/skia/include/core/SkEncodedImageFormat.h"
#include "third_party/skia/include/core/SkImageEncoder.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "third_party/skia/include/core/SkSerialProcs.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/core/SkSurfaceCharacterization.h"
#include "third_party/skia/include/utils/SkBase64.h"

#ifdef ERROR
#undef ERROR
#endif

namespace shell {

Rasterizer::Rasterizer(blink::TaskRunners task_runners)
    : Rasterizer(std::move(task_runners),
                 std::make_unique<flow::CompositorContext>()) {}

Rasterizer::Rasterizer(
    blink::TaskRunners task_runners,
    std::unique_ptr<flow::CompositorContext> compositor_context)
    : task_runners_(std::move(task_runners)),
      compositor_context_(std::move(compositor_context)),
      weak_factory_(this) {
  FML_DCHECK(compositor_context_);
}

Rasterizer::~Rasterizer() = default;

fml::WeakPtr<Rasterizer> Rasterizer::GetWeakPtr() const {
  return weak_factory_.GetWeakPtr();
}

void Rasterizer::Setup(std::unique_ptr<Surface> surface) {
  surface_ = std::move(surface);
  compositor_context_->OnGrContextCreated();
}

void Rasterizer::Teardown() {
  compositor_context_->OnGrContextDestroyed();
  surface_.reset();
  last_layer_tree_.reset();
}

flow::TextureRegistry* Rasterizer::GetTextureRegistry() {
  return &compositor_context_->texture_registry();
}

flow::LayerTree* Rasterizer::GetLastLayerTree() {
  return last_layer_tree_.get();
}

void Rasterizer::DrawLastLayerTree() {
  if (!last_layer_tree_ || !surface_) {
    return;
  }
  DrawToSurface(*last_layer_tree_);
}

void Rasterizer::Draw(
    fml::RefPtr<flutter::Pipeline<flow::LayerTree>> pipeline) {
  TRACE_EVENT0("flutter", "GPURasterizer::Draw");

  flutter::Pipeline<flow::LayerTree>::Consumer consumer =
      std::bind(&Rasterizer::DoDraw, this, std::placeholders::_1);

  // Consume as many pipeline items as possible. But yield the event loop
  // between successive tries.
  switch (pipeline->Consume(consumer)) {
    case flutter::PipelineConsumeResult::MoreAvailable: {
      task_runners_.GetGPUTaskRunner()->PostTask(
          [weak_this = weak_factory_.GetWeakPtr(), pipeline]() {
            if (weak_this) {
              weak_this->Draw(pipeline);
            }
          });
      break;
    }
    default:
      break;
  }
}

void Rasterizer::DoDraw(std::unique_ptr<flow::LayerTree> layer_tree) {
  if (!layer_tree || !surface_) {
    return;
  }

  if (DrawToSurface(*layer_tree)) {
    last_layer_tree_ = std::move(layer_tree);
  }
}

bool Rasterizer::DrawToSurface(flow::LayerTree& layer_tree) {
  FML_DCHECK(surface_);

  auto frame = surface_->AcquireFrame(layer_tree.frame_size());

  if (frame == nullptr) {
    return false;
  }

  // There is no way for the compositor to know how long the layer tree
  // construction took. Fortunately, the layer tree does. Grab that time
  // for instrumentation.
  compositor_context_->engine_time().SetLapTime(layer_tree.construction_time());

  auto canvas = frame->SkiaCanvas();

  auto compositor_frame = compositor_context_->AcquireFrame(
      surface_->GetContext(), canvas, surface_->GetRootTransformation(), true);

  if (canvas) {
    canvas->clear(SK_ColorTRANSPARENT);
  }

  if (compositor_frame && compositor_frame->Raster(layer_tree, false)) {
    frame->Submit();
    FireNextFrameCallbackIfPresent();
    return true;
  }

  return false;
}

static sk_sp<SkData> SerializeTypeface(SkTypeface* typeface, void* ctx) {
  return typeface->serialize(SkTypeface::SerializeBehavior::kDoIncludeData);
}

static sk_sp<SkData> ScreenshotLayerTreeAsPicture(
    flow::LayerTree* tree,
    flow::CompositorContext& compositor_context) {
  FML_DCHECK(tree != nullptr);
  SkPictureRecorder recorder;
  recorder.beginRecording(
      SkRect::MakeWH(tree->frame_size().width(), tree->frame_size().height()));

  SkMatrix root_surface_transformation;
  root_surface_transformation.reset();

  auto frame =
      compositor_context.AcquireFrame(nullptr, recorder.getRecordingCanvas(),
                                      root_surface_transformation, false);

  frame->Raster(*tree, true);

  SkSerialProcs procs = {0};
  procs.fTypefaceProc = SerializeTypeface;

  return recorder.finishRecordingAsPicture()->serialize(&procs);
}

static sk_sp<SkSurface> CreateSnapshotSurface(GrContext* surface_context,
                                              const SkISize& size) {
  const auto image_info = SkImageInfo::MakeN32Premul(size);
  if (surface_context) {
    // There is a rendering surface that may contain textures that are going to
    // be referenced in the layer tree about to be drawn.
    return SkSurface::MakeRenderTarget(surface_context,  //
                                       SkBudgeted::kNo,  //
                                       image_info        //
    );
  }

  // There is no rendering surface, assume no GPU textures are present and
  // create a raster surface.
  return SkSurface::MakeRaster(image_info);
}

static sk_sp<SkData> ScreenshotLayerTreeAsImage(
    flow::LayerTree* tree,
    flow::CompositorContext& compositor_context,
    GrContext* surface_context,
    bool compressed) {
  // Attempt to create a snapshot surface depending on whether we have access to
  // a valid GPU rendering context.
  auto snapshot_surface =
      CreateSnapshotSurface(surface_context, tree->frame_size());
  if (snapshot_surface == nullptr) {
    FML_LOG(ERROR) << "Screenshot: unable to create snapshot surface";
    return nullptr;
  }

  // Draw the current layer tree into the snapshot surface.
  auto canvas = snapshot_surface->getCanvas();

  // There is no root surface transformation for the screenshot layer. Reset the
  // matrix to identity.
  SkMatrix root_surface_transformation;
  root_surface_transformation.reset();

  auto frame = compositor_context.AcquireFrame(
      surface_context, canvas, root_surface_transformation, false);
  canvas->clear(SK_ColorTRANSPARENT);
  frame->Raster(*tree, true);
  canvas->flush();

  // Prepare an image from the surface, this image may potentially be on th GPU.
  auto potentially_gpu_snapshot = snapshot_surface->makeImageSnapshot();
  if (!potentially_gpu_snapshot) {
    FML_LOG(ERROR) << "Screenshot: unable to make image screenshot";
    return nullptr;
  }

  // Copy the GPU image snapshot into CPU memory.
  auto cpu_snapshot = potentially_gpu_snapshot->makeRasterImage();
  if (!cpu_snapshot) {
    FML_LOG(ERROR) << "Screenshot: unable to make raster image";
    return nullptr;
  }

  // If the caller want the pixels to be compressed, there is a Skia utility to
  // compress to PNG. Use that.
  if (compressed) {
    return cpu_snapshot->encodeToData();
  }

  // Copy it into a bitmap and return the same.
  SkPixmap pixmap;
  if (!cpu_snapshot->peekPixels(&pixmap)) {
    FML_LOG(ERROR) << "Screenshot: unable to obtain bitmap pixels";
    return nullptr;
  }

  return SkData::MakeWithCopy(pixmap.addr32(), pixmap.computeByteSize());
}

Rasterizer::Screenshot Rasterizer::ScreenshotLastLayerTree(
    Rasterizer::ScreenshotType type,
    bool base64_encode) {
  auto layer_tree = GetLastLayerTree();
  if (layer_tree == nullptr) {
    FML_LOG(ERROR) << "Last layer tree was null when screenshotting.";
    return {};
  }

  sk_sp<SkData> data = nullptr;

  GrContext* surface_context = surface_ ? surface_->GetContext() : nullptr;

  switch (type) {
    case ScreenshotType::SkiaPicture:
      data = ScreenshotLayerTreeAsPicture(layer_tree, *compositor_context_);
      break;
    case ScreenshotType::UncompressedImage:
      data = ScreenshotLayerTreeAsImage(layer_tree, *compositor_context_,
                                        surface_context, false);
      break;
    case ScreenshotType::CompressedImage:
      data = ScreenshotLayerTreeAsImage(layer_tree, *compositor_context_,
                                        surface_context, true);
      break;
  }

  if (data == nullptr) {
    FML_LOG(ERROR) << "Screenshot data was null.";
    return {};
  }

  if (base64_encode) {
    size_t b64_size = SkBase64::Encode(data->data(), data->size(), nullptr);
    auto b64_data = SkData::MakeUninitialized(b64_size);
    SkBase64::Encode(data->data(), data->size(), b64_data->writable_data());
    return Rasterizer::Screenshot{b64_data, layer_tree->frame_size()};
  }

  return Rasterizer::Screenshot{data, layer_tree->frame_size()};
}

void Rasterizer::SetNextFrameCallback(fml::closure callback) {
  next_frame_callback_ = callback;
}

void Rasterizer::FireNextFrameCallbackIfPresent() {
  if (!next_frame_callback_) {
    return;
  }
  // It is safe for the callback to set a new callback.
  auto callback = next_frame_callback_;
  next_frame_callback_ = nullptr;
  callback();
}

}  // namespace shell
<|endoftext|>


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

// geometry/VertexDataManager.h: Defines the VertexDataManager, a class that
// runs the Buffer translation process.

#include "geometry/VertexDataManager.h"

#include "common/debug.h"
#include "Program.h"

#include "Buffer.h"
#include "geometry/backend.h"
#include "geometry/IndexDataManager.h"

namespace
{
    enum { INITIAL_STREAM_BUFFER_SIZE = 1024*1024 };
}

namespace gl
{

VertexDataManager::VertexDataManager(Context *context, BufferBackEnd *backend)
    : mContext(context), mBackend(backend), mDirtyCurrentValues(true)
{
    mStreamBuffer = mBackend->createVertexBuffer(INITIAL_STREAM_BUFFER_SIZE);
    try
    {
        mCurrentValueBuffer = mBackend->createVertexBuffer(4*sizeof(float)*MAX_VERTEX_ATTRIBS);
    }
    catch (...)
    {
        delete mStreamBuffer;
        throw;
    }
}

VertexDataManager::~VertexDataManager()
{
    delete mStreamBuffer;
    delete mCurrentValueBuffer;
}

VertexDataManager::ArrayTranslationHelper::ArrayTranslationHelper(GLint first, GLsizei count)
    : mFirst(first), mCount(count)
{
}

void VertexDataManager::ArrayTranslationHelper::translate(const FormatConverter &converter, GLsizei stride, const void *source, void *dest)
{
    converter.convertArray(source, stride, mCount, dest);
}

VertexDataManager::IndexedTranslationHelper::IndexedTranslationHelper(const Index *indices, Index minIndex, GLsizei count)
    : mIndices(indices), mMinIndex(minIndex), mCount(count)
{
}

void VertexDataManager::IndexedTranslationHelper::translate(const FormatConverter &converter, GLsizei stride, const void *source, void *dest)
{
    converter.convertIndexed(source, stride, mMinIndex, mCount, mIndices, dest);
}

std::bitset<MAX_VERTEX_ATTRIBS> VertexDataManager::activeAttribs()
{
    std::bitset<MAX_VERTEX_ATTRIBS> active;

    Program *p = mContext->getCurrentProgram();

    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    {
        if (p->isActiveAttribute(i))
            active[i] = true;
    }

    return active;
}

GLenum VertexDataManager::preRenderValidate(GLint start, GLsizei count,
                                            TranslatedAttribute *outAttribs)

{
    ArrayTranslationHelper translationHelper(start, count);

    return internalPreRenderValidate(mContext->vertexAttribute, activeAttribs(), start, start+count-1, &translationHelper, outAttribs);
}

GLenum VertexDataManager::preRenderValidate(const TranslatedIndexData &indexInfo,
                                            TranslatedAttribute *outAttribs)

{
    IndexedTranslationHelper translationHelper(indexInfo.indices, indexInfo.minIndex, indexInfo.count);

    return internalPreRenderValidate(mContext->vertexAttribute, activeAttribs(), indexInfo.minIndex, indexInfo.maxIndex, &translationHelper, outAttribs);
}

GLenum VertexDataManager::internalPreRenderValidate(const AttributeState *attribs,
                                                    const std::bitset<MAX_VERTEX_ATTRIBS> &activeAttribs,
                                                    Index minIndex,
                                                    Index maxIndex,
                                                    TranslationHelper *translator,
                                                    TranslatedAttribute *translated)
{
    std::bitset<MAX_VERTEX_ATTRIBS> translateOrLift;

    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    {
        if (!activeAttribs[i] && attribs[i].mEnabled && attribs[i].mBoundBuffer != 0 && !mContext->getBuffer(attribs[i].mBoundBuffer))
            return GL_INVALID_OPERATION;
    }

    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    {
        translated[i].enabled = activeAttribs[i];
    }

    processNonArrayAttributes(attribs, activeAttribs, translated);

    // Handle the identity-mapped attributes.

    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    {
        if (activeAttribs[i] && attribs[i].mEnabled)
        {
            if (attribs[i].mBoundBuffer != 0 && mBackend->getFormatConverter(attribs[i].mType, attribs[i].mSize, attribs[i].mNormalized).identity)
            {
                std::size_t stride = interpretGlStride(attribs[i]);
                std::size_t offset = static_cast<std::size_t>(static_cast<const char*>(attribs[i].mPointer) - static_cast<const char*>(NULL)) + translated[i].stride * minIndex;

                if (mBackend->validateStream(attribs[i].mType, attribs[i].mSize, stride, offset))
                {
                    translated[i].type = attribs[i].mType;
                    translated[i].size = attribs[i].mSize;
                    translated[i].normalized = attribs[i].mNormalized;
                    translated[i].stride = stride;
                    translated[i].offset = offset;
                    translated[i].buffer = mContext->getBuffer(attribs[i].mBoundBuffer)->identityBuffer();
                }
                else
                {
                    translateOrLift[i] = true;
                }
            }
            else
            {
                translateOrLift[i] = true;
            }
        }
    }

    // Handle any attributes needing translation or lifting.
    if (translateOrLift.any())
    {
        std::size_t count = maxIndex - minIndex + 1;

        std::size_t requiredSpace = 0;

        for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
        {
            if (translateOrLift[i])
            {
                requiredSpace += spaceRequired(attribs[i], count);
            }
        }

        if (requiredSpace > mStreamBuffer->size())
        {
            std::size_t newSize = std::max(requiredSpace, 3 * mStreamBuffer->size() / 2); // 1.5 x mStreamBuffer->size() is arbitrary and should be checked to see we don't have too many reallocations.

            TranslatedVertexBuffer *newStreamBuffer = mBackend->createVertexBuffer(newSize);

            delete mStreamBuffer;
            mStreamBuffer = newStreamBuffer;
        }

        mStreamBuffer->reserveSpace(requiredSpace);

        for (size_t i = 0; i < MAX_VERTEX_ATTRIBS; i++)
        {
            if (translateOrLift[i])
            {
                FormatConverter formatConverter = mBackend->getFormatConverter(attribs[i].mType, attribs[i].mSize, attribs[i].mNormalized);

                translated[i].type = attribs[i].mType;
                translated[i].size = attribs[i].mSize;
                translated[i].normalized = attribs[i].mNormalized;
                translated[i].stride = formatConverter.outputVertexSize;
                translated[i].buffer = mStreamBuffer;

                void *output = mStreamBuffer->map(spaceRequired(attribs[i], count), &translated[i].offset);

                const void *input;
                if (attribs[i].mBoundBuffer)
                {
                    input = mContext->getBuffer(attribs[i].mBoundBuffer)->data();
                    input = static_cast<const char*>(input) + reinterpret_cast<size_t>(attribs[i].mPointer);
                }
                else
                {
                    input = attribs[i].mPointer;
                }

                size_t inputStride = interpretGlStride(attribs[i]);

                input = static_cast<const char*>(input) + inputStride * minIndex;

                translator->translate(formatConverter, interpretGlStride(attribs[i]), input, output);

                mStreamBuffer->unmap();
            }
        }
    }

    return GL_NO_ERROR;
}

void VertexDataManager::reloadCurrentValues(const AttributeState *attribs, std::size_t *offset)
{
    if (mDirtyCurrentValues)
    {
        std::size_t totalSize = 4 * sizeof(float) * MAX_VERTEX_ATTRIBS;

        mCurrentValueBuffer->reserveSpace(totalSize);

        float* p = static_cast<float*>(mCurrentValueBuffer->map(totalSize, offset));

        for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
        {
            memcpy(&p[i*4], attribs[i].mCurrentValue, sizeof(attribs[i].mCurrentValue)); // FIXME: this should be doing a translation. This assumes that GL_FLOATx4 is supported.
        }

        mCurrentValueBuffer->unmap();

        mDirtyCurrentValues = false;
    }
}

std::size_t VertexDataManager::typeSize(GLenum type) const
{
    switch (type)
    {
      case GL_BYTE: case GL_UNSIGNED_BYTE: return sizeof(GLbyte);
      case GL_SHORT: case GL_UNSIGNED_SHORT: return sizeof(GLshort);
      case GL_FIXED: return sizeof(GLfixed);
      case GL_FLOAT: return sizeof(GLfloat);
      default: UNREACHABLE(); return sizeof(GLfloat);
    }
}

std::size_t VertexDataManager::interpretGlStride(const AttributeState &attrib) const
{
    return attrib.mStride ? attrib.mStride : typeSize(attrib.mType) * attrib.mSize;
}

// Round up x (>=0) to the next multiple of multiple (>0).
// 0 rounds up to 0.
std::size_t VertexDataManager::roundUp(std::size_t x, std::size_t multiple) const
{
    ASSERT(x >= 0);
    ASSERT(multiple > 0);

    std::size_t remainder = x % multiple;
    if (remainder != 0)
    {
        return x + multiple - remainder;
    }
    else
    {
        return x;
    }
}

std::size_t VertexDataManager::spaceRequired(const AttributeState &attrib, std::size_t maxVertex) const
{
    std::size_t size = mBackend->getFormatConverter(attrib.mType, attrib.mSize, attrib.mNormalized).outputVertexSize;
    size *= maxVertex;

    return roundUp(size, 4 * sizeof(GLfloat));
}

void VertexDataManager::processNonArrayAttributes(const AttributeState *attribs, const std::bitset<MAX_VERTEX_ATTRIBS> &activeAttribs, TranslatedAttribute *translated)
{
    bool usesCurrentValues = false;

    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    {
        if (activeAttribs[i] && !attribs[i].mEnabled)
        {
            usesCurrentValues = true;
            break;
        }
    }

    if (usesCurrentValues)
    {
        std::size_t currentValueOffset;

        reloadCurrentValues(attribs, &currentValueOffset);

        for (std::size_t i = 0; i < MAX_VERTEX_ATTRIBS; i++)
        {
            if (activeAttribs[i] && !attribs[i].mEnabled)
            {
                translated[i].buffer = mCurrentValueBuffer;

                translated[i].type = GL_FLOAT;
                translated[i].size = 4;
                translated[i].normalized = false;
                translated[i].stride = 0;
                translated[i].offset = currentValueOffset + 4 * sizeof(float) * i;
            }
        }
    }
}

}
<commit_msg>Accidentally moved a read of translated[i].stride before the write.<commit_after>//
// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

// geometry/VertexDataManager.h: Defines the VertexDataManager, a class that
// runs the Buffer translation process.

#include "geometry/VertexDataManager.h"

#include "common/debug.h"
#include "Program.h"

#include "Buffer.h"
#include "geometry/backend.h"
#include "geometry/IndexDataManager.h"

namespace
{
    enum { INITIAL_STREAM_BUFFER_SIZE = 1024*1024 };
}

namespace gl
{

VertexDataManager::VertexDataManager(Context *context, BufferBackEnd *backend)
    : mContext(context), mBackend(backend), mDirtyCurrentValues(true)
{
    mStreamBuffer = mBackend->createVertexBuffer(INITIAL_STREAM_BUFFER_SIZE);
    try
    {
        mCurrentValueBuffer = mBackend->createVertexBuffer(4*sizeof(float)*MAX_VERTEX_ATTRIBS);
    }
    catch (...)
    {
        delete mStreamBuffer;
        throw;
    }
}

VertexDataManager::~VertexDataManager()
{
    delete mStreamBuffer;
    delete mCurrentValueBuffer;
}

VertexDataManager::ArrayTranslationHelper::ArrayTranslationHelper(GLint first, GLsizei count)
    : mFirst(first), mCount(count)
{
}

void VertexDataManager::ArrayTranslationHelper::translate(const FormatConverter &converter, GLsizei stride, const void *source, void *dest)
{
    converter.convertArray(source, stride, mCount, dest);
}

VertexDataManager::IndexedTranslationHelper::IndexedTranslationHelper(const Index *indices, Index minIndex, GLsizei count)
    : mIndices(indices), mMinIndex(minIndex), mCount(count)
{
}

void VertexDataManager::IndexedTranslationHelper::translate(const FormatConverter &converter, GLsizei stride, const void *source, void *dest)
{
    converter.convertIndexed(source, stride, mMinIndex, mCount, mIndices, dest);
}

std::bitset<MAX_VERTEX_ATTRIBS> VertexDataManager::activeAttribs()
{
    std::bitset<MAX_VERTEX_ATTRIBS> active;

    Program *p = mContext->getCurrentProgram();

    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    {
        if (p->isActiveAttribute(i))
            active[i] = true;
    }

    return active;
}

GLenum VertexDataManager::preRenderValidate(GLint start, GLsizei count,
                                            TranslatedAttribute *outAttribs)

{
    ArrayTranslationHelper translationHelper(start, count);

    return internalPreRenderValidate(mContext->vertexAttribute, activeAttribs(), start, start+count-1, &translationHelper, outAttribs);
}

GLenum VertexDataManager::preRenderValidate(const TranslatedIndexData &indexInfo,
                                            TranslatedAttribute *outAttribs)

{
    IndexedTranslationHelper translationHelper(indexInfo.indices, indexInfo.minIndex, indexInfo.count);

    return internalPreRenderValidate(mContext->vertexAttribute, activeAttribs(), indexInfo.minIndex, indexInfo.maxIndex, &translationHelper, outAttribs);
}

GLenum VertexDataManager::internalPreRenderValidate(const AttributeState *attribs,
                                                    const std::bitset<MAX_VERTEX_ATTRIBS> &activeAttribs,
                                                    Index minIndex,
                                                    Index maxIndex,
                                                    TranslationHelper *translator,
                                                    TranslatedAttribute *translated)
{
    std::bitset<MAX_VERTEX_ATTRIBS> translateOrLift;

    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    {
        if (!activeAttribs[i] && attribs[i].mEnabled && attribs[i].mBoundBuffer != 0 && !mContext->getBuffer(attribs[i].mBoundBuffer))
            return GL_INVALID_OPERATION;
    }

    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    {
        translated[i].enabled = activeAttribs[i];
    }

    processNonArrayAttributes(attribs, activeAttribs, translated);

    // Handle the identity-mapped attributes.

    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    {
        if (activeAttribs[i] && attribs[i].mEnabled)
        {
            if (attribs[i].mBoundBuffer != 0 && mBackend->getFormatConverter(attribs[i].mType, attribs[i].mSize, attribs[i].mNormalized).identity)
            {
                std::size_t stride = interpretGlStride(attribs[i]);
                std::size_t offset = static_cast<std::size_t>(static_cast<const char*>(attribs[i].mPointer) - static_cast<const char*>(NULL)) + stride * minIndex;

                if (mBackend->validateStream(attribs[i].mType, attribs[i].mSize, stride, offset))
                {
                    translated[i].type = attribs[i].mType;
                    translated[i].size = attribs[i].mSize;
                    translated[i].normalized = attribs[i].mNormalized;
                    translated[i].stride = stride;
                    translated[i].offset = offset;
                    translated[i].buffer = mContext->getBuffer(attribs[i].mBoundBuffer)->identityBuffer();
                }
                else
                {
                    translateOrLift[i] = true;
                }
            }
            else
            {
                translateOrLift[i] = true;
            }
        }
    }

    // Handle any attributes needing translation or lifting.
    if (translateOrLift.any())
    {
        std::size_t count = maxIndex - minIndex + 1;

        std::size_t requiredSpace = 0;

        for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
        {
            if (translateOrLift[i])
            {
                requiredSpace += spaceRequired(attribs[i], count);
            }
        }

        if (requiredSpace > mStreamBuffer->size())
        {
            std::size_t newSize = std::max(requiredSpace, 3 * mStreamBuffer->size() / 2); // 1.5 x mStreamBuffer->size() is arbitrary and should be checked to see we don't have too many reallocations.

            TranslatedVertexBuffer *newStreamBuffer = mBackend->createVertexBuffer(newSize);

            delete mStreamBuffer;
            mStreamBuffer = newStreamBuffer;
        }

        mStreamBuffer->reserveSpace(requiredSpace);

        for (size_t i = 0; i < MAX_VERTEX_ATTRIBS; i++)
        {
            if (translateOrLift[i])
            {
                FormatConverter formatConverter = mBackend->getFormatConverter(attribs[i].mType, attribs[i].mSize, attribs[i].mNormalized);

                translated[i].type = attribs[i].mType;
                translated[i].size = attribs[i].mSize;
                translated[i].normalized = attribs[i].mNormalized;
                translated[i].stride = formatConverter.outputVertexSize;
                translated[i].buffer = mStreamBuffer;

                void *output = mStreamBuffer->map(spaceRequired(attribs[i], count), &translated[i].offset);

                const void *input;
                if (attribs[i].mBoundBuffer)
                {
                    input = mContext->getBuffer(attribs[i].mBoundBuffer)->data();
                    input = static_cast<const char*>(input) + reinterpret_cast<size_t>(attribs[i].mPointer);
                }
                else
                {
                    input = attribs[i].mPointer;
                }

                size_t inputStride = interpretGlStride(attribs[i]);

                input = static_cast<const char*>(input) + inputStride * minIndex;

                translator->translate(formatConverter, interpretGlStride(attribs[i]), input, output);

                mStreamBuffer->unmap();
            }
        }
    }

    return GL_NO_ERROR;
}

void VertexDataManager::reloadCurrentValues(const AttributeState *attribs, std::size_t *offset)
{
    if (mDirtyCurrentValues)
    {
        std::size_t totalSize = 4 * sizeof(float) * MAX_VERTEX_ATTRIBS;

        mCurrentValueBuffer->reserveSpace(totalSize);

        float* p = static_cast<float*>(mCurrentValueBuffer->map(totalSize, offset));

        for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
        {
            memcpy(&p[i*4], attribs[i].mCurrentValue, sizeof(attribs[i].mCurrentValue)); // FIXME: this should be doing a translation. This assumes that GL_FLOATx4 is supported.
        }

        mCurrentValueBuffer->unmap();

        mDirtyCurrentValues = false;
    }
}

std::size_t VertexDataManager::typeSize(GLenum type) const
{
    switch (type)
    {
      case GL_BYTE: case GL_UNSIGNED_BYTE: return sizeof(GLbyte);
      case GL_SHORT: case GL_UNSIGNED_SHORT: return sizeof(GLshort);
      case GL_FIXED: return sizeof(GLfixed);
      case GL_FLOAT: return sizeof(GLfloat);
      default: UNREACHABLE(); return sizeof(GLfloat);
    }
}

std::size_t VertexDataManager::interpretGlStride(const AttributeState &attrib) const
{
    return attrib.mStride ? attrib.mStride : typeSize(attrib.mType) * attrib.mSize;
}

// Round up x (>=0) to the next multiple of multiple (>0).
// 0 rounds up to 0.
std::size_t VertexDataManager::roundUp(std::size_t x, std::size_t multiple) const
{
    ASSERT(x >= 0);
    ASSERT(multiple > 0);

    std::size_t remainder = x % multiple;
    if (remainder != 0)
    {
        return x + multiple - remainder;
    }
    else
    {
        return x;
    }
}

std::size_t VertexDataManager::spaceRequired(const AttributeState &attrib, std::size_t maxVertex) const
{
    std::size_t size = mBackend->getFormatConverter(attrib.mType, attrib.mSize, attrib.mNormalized).outputVertexSize;
    size *= maxVertex;

    return roundUp(size, 4 * sizeof(GLfloat));
}

void VertexDataManager::processNonArrayAttributes(const AttributeState *attribs, const std::bitset<MAX_VERTEX_ATTRIBS> &activeAttribs, TranslatedAttribute *translated)
{
    bool usesCurrentValues = false;

    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    {
        if (activeAttribs[i] && !attribs[i].mEnabled)
        {
            usesCurrentValues = true;
            break;
        }
    }

    if (usesCurrentValues)
    {
        std::size_t currentValueOffset;

        reloadCurrentValues(attribs, &currentValueOffset);

        for (std::size_t i = 0; i < MAX_VERTEX_ATTRIBS; i++)
        {
            if (activeAttribs[i] && !attribs[i].mEnabled)
            {
                translated[i].buffer = mCurrentValueBuffer;

                translated[i].type = GL_FLOAT;
                translated[i].size = 4;
                translated[i].normalized = false;
                translated[i].stride = 0;
                translated[i].offset = currentValueOffset + 4 * sizeof(float) * i;
            }
        }
    }
}

}
<|endoftext|>