<commit_before>/*
  Q Light Controller
  channelselection.cpp

  Copyright (c) Massimo Callegari

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

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

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

#include <QPushButton>
#include <QDebug>

#include "selectinputchannel.h"
#include "addchannelsgroup.h"
#include "qlcfixturemode.h"
#include "qlcfixturedef.h"
#include "channelsgroup.h"
#include "fixture.h"
#include "doc.h"

#define KColumnName  0
#define KColumnType  1
#define KColumnGroup 2
#define KColumnChIdx 3
#define KColumnID    4

AddChannelsGroup::AddChannelsGroup(QWidget* parent, Doc* doc, ChannelsGroup *group)
    : QDialog(parent)
    , m_doc(doc)
    , m_chansGroup(group)
    , m_checkedChannels(0)
    , m_isUpdating(false)
{
    Q_ASSERT(doc != NULL);
    Q_ASSERT(m_chansGroup != NULL);

    setupUi(this);

    m_tree->header()->setSectionHidden(KColumnID, true);
    m_tree->setSelectionMode(QAbstractItemView::MultiSelection);
    m_tree->setAlternatingRowColors(true);
    m_tree->setIconSize(QSize(20, 20));

    m_groupNameEdit->setText(group->name());

    QList <SceneValue> chans = group->getChannels();
    int ch = 0;

    foreach (Fixture* fxi, m_doc->fixtures())
    {
        QTreeWidgetItem *topItem = NULL;
        quint32 uni = fxi->universe();
        for (int i = 0; i < m_tree->topLevelItemCount(); i++)
        {
            QTreeWidgetItem* tItem = m_tree->topLevelItem(i);
            quint32 tUni = tItem->text(KColumnID).toUInt();
            if (tUni == uni)
            {
                topItem = tItem;
                break;
            }
        }
        // Haven't found this universe node ? Create it.
        if (topItem == NULL)
        {
            topItem = new QTreeWidgetItem(m_tree);
            topItem->setText(KColumnName, tr("Universe %1").arg(uni + 1));
            topItem->setText(KColumnID, QString::number(uni));
            topItem->setExpanded(true);
        }

        QTreeWidgetItem *fItem = new QTreeWidgetItem(topItem);
        fItem->setExpanded(true);
        fItem->setText(KColumnName, fxi->name());
        fItem->setIcon(KColumnName, fxi->getIconFromType(fxi->type()));
        fItem->setText(KColumnID, QString::number(fxi->id()));

        for (quint32 c = 0; c < fxi->channels(); c++)
        {
            const QLCChannel* channel = fxi->channel(c);
            QTreeWidgetItem *item = new QTreeWidgetItem(fItem);
            item->setText(KColumnName, QString("%1:%2").arg(c + 1)
                          .arg(channel->name()));
            item->setIcon(KColumnName, channel->getIconFromGroup(channel->group()));
            if (channel->group() == QLCChannel::Intensity &&
                channel->colour() != QLCChannel::NoColour)
                item->setText(KColumnType, QLCChannel::colourToString(channel->colour()));
            else
                item->setText(KColumnType, QLCChannel::groupToString(channel->group()));

            item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
            if (chans.count() > ch &&
                chans.at(ch).fxi == fxi->id() &&
                chans.at(ch).channel == c)
            {
                item->setCheckState(KColumnGroup, Qt::Checked);
                m_checkedChannels++;
                ch++;
            }
            else
                item->setCheckState(KColumnGroup, Qt::Unchecked);
            item->setText(KColumnID, QString::number(fxi->id()));
            item->setText(KColumnChIdx, QString::number(c));
        }
    }
    m_tree->resizeColumnToContents(KColumnName);
    m_tree->resizeColumnToContents(KColumnType);
    m_tree->resizeColumnToContents(KColumnGroup);

    m_inputSource = group->inputSource();
    updateInputSource();

    if (m_checkedChannels == 0)
        m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);

    connect(m_tree, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
            this, SLOT(slotItemChecked(QTreeWidgetItem*, int)));

    connect(m_autoDetectInputButton, SIGNAL(toggled(bool)),
            this, SLOT(slotAutoDetectInputToggled(bool)));
    connect(m_chooseInputButton, SIGNAL(clicked()),
            this, SLOT(slotChooseInputClicked()));
}

AddChannelsGroup::~AddChannelsGroup()
{
}

void AddChannelsGroup::accept()
{
    m_chansGroup->resetChannels();

    for (int t = 0; t < m_tree->topLevelItemCount(); t++)
    {
        QTreeWidgetItem *uniItem = m_tree->topLevelItem(t);
        for (int f = 0; f < uniItem->childCount(); f++)
        {
            QTreeWidgetItem *fixItem = uniItem->child(f);
            quint32 fxID = fixItem->text(KColumnID).toUInt();
            Fixture *fxi = m_doc->fixture(fxID);
            if (fxi != NULL)
            {
                for (int c = 0; c < fixItem->childCount(); c++)
                {
                    QTreeWidgetItem *chanItem = fixItem->child(c);
                    if (chanItem->checkState(KColumnGroup) == Qt::Checked)
                    {
                        m_chansGroup->addChannel(QString(chanItem->text(KColumnID)).toUInt(),
                                                 QString(chanItem->text(KColumnChIdx)).toUInt());
                        qDebug() << "Added channel with ID:" << chanItem->text(KColumnID) << ", and channel:" << chanItem->text(KColumnChIdx);
                    }
                }
            }
        }
    }

    m_chansGroup->setName(m_groupNameEdit->text());
    m_chansGroup->setInputSource(m_inputSource);
    QDialog::accept();
}

void AddChannelsGroup::slotItemChecked(QTreeWidgetItem *item, int col)
{
    if (m_isUpdating == true || col != KColumnGroup || item->text(KColumnID).isEmpty())
        return;

    m_isUpdating = true;

    if (m_applyAllCheck->isChecked() == false)
    {
        if (item->checkState(col) == Qt::Checked)
            m_checkedChannels++;
        else
            m_checkedChannels--;
    }
    else
    {
        Fixture *fixture = m_doc->fixture(item->text(KColumnID).toUInt());
        if (fixture == NULL)
            return;

        const QLCFixtureDef *def = fixture->fixtureDef();
        if (def == NULL)
            return;

        QString manufacturer = def->manufacturer();
        QString model = def->model();
        int chIdx = item->text(KColumnChIdx).toInt();
        Qt::CheckState enable = item->checkState(KColumnGroup);

        qDebug() << "Manuf:" << manufacturer << ", model:" << model << ", ch:" << chIdx;

        for (int t = 0; t < m_tree->topLevelItemCount(); t++)
        {
            QTreeWidgetItem *uniItem = m_tree->topLevelItem(t);
            for (int f = 0; f < uniItem->childCount(); f++)
            {
                QTreeWidgetItem *fixItem = uniItem->child(f);
                quint32 fxID = fixItem->text(KColumnID).toUInt();
                Fixture *fxi = m_doc->fixture(fxID);
                if (fxi != NULL)
                {
                    const QLCFixtureDef *tmpDef = fxi->fixtureDef();
                    if (tmpDef != NULL)
                    {
                        QString tmpManuf = tmpDef->manufacturer();
                        QString tmpModel = tmpDef->model();
                        if (tmpManuf == manufacturer && tmpModel == model)
                        {
                            QTreeWidgetItem* item = fixItem->child(chIdx);
                            if (item != NULL)
                            {
                                item->setCheckState(KColumnGroup, enable);
                                if (enable == Qt::Checked)
                                    m_checkedChannels++;
                                else
                                    m_checkedChannels--;
                            }
                        }
                    }
                }
            }
        }
    }

    if (m_checkedChannels > 0)
        m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
    else
        m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);

    m_isUpdating = false;
}

void AddChannelsGroup::slotAutoDetectInputToggled(bool checked)
{
    if (checked == true)
    {
        connect(m_doc->inputMap(), SIGNAL(inputValueChanged(quint32,quint32,uchar)),
                this, SLOT(slotInputValueChanged(quint32,quint32)));
    }
    else
    {
        disconnect(m_doc->inputMap(), SIGNAL(inputValueChanged(quint32,quint32,uchar)),
                   this, SLOT(slotInputValueChanged(quint32,quint32)));
    }
}

void AddChannelsGroup::slotInputValueChanged(quint32 universe, quint32 channel)
{
    m_inputSource = QLCInputSource(universe, channel);
    updateInputSource();
}

void AddChannelsGroup::slotChooseInputClicked()
{
    SelectInputChannel sic(this, m_doc->inputMap());
    if (sic.exec() == QDialog::Accepted)
    {
        m_inputSource = QLCInputSource(sic.universe(), sic.channel());
        updateInputSource();
    }
}

void AddChannelsGroup::updateInputSource()
{
    QString uniName;
    QString chName;

    if (m_doc->inputMap()->inputSourceNames(m_inputSource, uniName, chName) == false)
    {
        uniName = KInputNone;
        chName = KInputNone;
    }

    m_inputUniverseEdit->setText(uniName);
    m_inputChannelEdit->setText(chName);
}

<commit_msg>Store status "Apply changes to all fixture of the same type" checkbox in channel group editor<commit_after>/*
  Q Light Controller
  addchannelsgroup.cpp

  Copyright (c) Massimo Callegari

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

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

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

#include <QPushButton>
#include <QDebug>
#include <QSettings>

#include "selectinputchannel.h"
#include "addchannelsgroup.h"
#include "qlcfixturemode.h"
#include "qlcfixturedef.h"
#include "channelsgroup.h"
#include "fixture.h"
#include "doc.h"

#define KColumnName  0
#define KColumnType  1
#define KColumnGroup 2
#define KColumnChIdx 3
#define KColumnID    4

#define SETTINGS_APPLYALL "addchannelsgroup/applyall"

AddChannelsGroup::AddChannelsGroup(QWidget* parent, Doc* doc, ChannelsGroup *group)
    : QDialog(parent)
    , m_doc(doc)
    , m_chansGroup(group)
    , m_checkedChannels(0)
    , m_isUpdating(false)
{
    Q_ASSERT(doc != NULL);
    Q_ASSERT(m_chansGroup != NULL);

    setupUi(this);

    m_tree->header()->setSectionHidden(KColumnID, true);
    m_tree->setSelectionMode(QAbstractItemView::MultiSelection);
    m_tree->setAlternatingRowColors(true);
    m_tree->setIconSize(QSize(20, 20));

    m_groupNameEdit->setText(group->name());

    QList <SceneValue> chans = group->getChannels();
    int ch = 0;

    foreach (Fixture* fxi, m_doc->fixtures())
    {
        QTreeWidgetItem *topItem = NULL;
        quint32 uni = fxi->universe();
        for (int i = 0; i < m_tree->topLevelItemCount(); i++)
        {
            QTreeWidgetItem* tItem = m_tree->topLevelItem(i);
            quint32 tUni = tItem->text(KColumnID).toUInt();
            if (tUni == uni)
            {
                topItem = tItem;
                break;
            }
        }
        // Haven't found this universe node ? Create it.
        if (topItem == NULL)
        {
            topItem = new QTreeWidgetItem(m_tree);
            topItem->setText(KColumnName, tr("Universe %1").arg(uni + 1));
            topItem->setText(KColumnID, QString::number(uni));
            topItem->setExpanded(true);
        }

        QTreeWidgetItem *fItem = new QTreeWidgetItem(topItem);
        fItem->setExpanded(true);
        fItem->setText(KColumnName, fxi->name());
        fItem->setIcon(KColumnName, fxi->getIconFromType(fxi->type()));
        fItem->setText(KColumnID, QString::number(fxi->id()));

        for (quint32 c = 0; c < fxi->channels(); c++)
        {
            const QLCChannel* channel = fxi->channel(c);
            QTreeWidgetItem *item = new QTreeWidgetItem(fItem);
            item->setText(KColumnName, QString("%1:%2").arg(c + 1)
                          .arg(channel->name()));
            item->setIcon(KColumnName, channel->getIconFromGroup(channel->group()));
            if (channel->group() == QLCChannel::Intensity &&
                channel->colour() != QLCChannel::NoColour)
                item->setText(KColumnType, QLCChannel::colourToString(channel->colour()));
            else
                item->setText(KColumnType, QLCChannel::groupToString(channel->group()));

            item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
            if (chans.count() > ch &&
                chans.at(ch).fxi == fxi->id() &&
                chans.at(ch).channel == c)
            {
                item->setCheckState(KColumnGroup, Qt::Checked);
                m_checkedChannels++;
                ch++;
            }
            else
                item->setCheckState(KColumnGroup, Qt::Unchecked);
            item->setText(KColumnID, QString::number(fxi->id()));
            item->setText(KColumnChIdx, QString::number(c));
        }
    }
    m_tree->resizeColumnToContents(KColumnName);
    m_tree->resizeColumnToContents(KColumnType);
    m_tree->resizeColumnToContents(KColumnGroup);

    QSettings settings;
    QVariant var = settings.value(SETTINGS_APPLYALL);
    if (var.isValid() == true)
    {
       m_applyAllCheck->setChecked(var.toBool());
    }

    m_inputSource = group->inputSource();
    updateInputSource();

    if (m_checkedChannels == 0)
        m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);

    connect(m_tree, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
            this, SLOT(slotItemChecked(QTreeWidgetItem*, int)));

    connect(m_autoDetectInputButton, SIGNAL(toggled(bool)),
            this, SLOT(slotAutoDetectInputToggled(bool)));
    connect(m_chooseInputButton, SIGNAL(clicked()),
            this, SLOT(slotChooseInputClicked()));
}

AddChannelsGroup::~AddChannelsGroup()
{
    QSettings settings;
    settings.setValue(SETTINGS_APPLYALL, m_applyAllCheck->isChecked());
}

void AddChannelsGroup::accept()
{
    m_chansGroup->resetChannels();

    for (int t = 0; t < m_tree->topLevelItemCount(); t++)
    {
        QTreeWidgetItem *uniItem = m_tree->topLevelItem(t);
        for (int f = 0; f < uniItem->childCount(); f++)
        {
            QTreeWidgetItem *fixItem = uniItem->child(f);
            quint32 fxID = fixItem->text(KColumnID).toUInt();
            Fixture *fxi = m_doc->fixture(fxID);
            if (fxi != NULL)
            {
                for (int c = 0; c < fixItem->childCount(); c++)
                {
                    QTreeWidgetItem *chanItem = fixItem->child(c);
                    if (chanItem->checkState(KColumnGroup) == Qt::Checked)
                    {
                        m_chansGroup->addChannel(QString(chanItem->text(KColumnID)).toUInt(),
                                                 QString(chanItem->text(KColumnChIdx)).toUInt());
                        qDebug() << "Added channel with ID:" << chanItem->text(KColumnID) << ", and channel:" << chanItem->text(KColumnChIdx);
                    }
                }
            }
        }
    }

    m_chansGroup->setName(m_groupNameEdit->text());
    m_chansGroup->setInputSource(m_inputSource);
    QDialog::accept();
}

void AddChannelsGroup::slotItemChecked(QTreeWidgetItem *item, int col)
{
    if (m_isUpdating == true || col != KColumnGroup || item->text(KColumnID).isEmpty())
        return;

    m_isUpdating = true;

    if (m_applyAllCheck->isChecked() == false)
    {
        if (item->checkState(col) == Qt::Checked)
            m_checkedChannels++;
        else
            m_checkedChannels--;
    }
    else
    {
        Fixture *fixture = m_doc->fixture(item->text(KColumnID).toUInt());
        if (fixture == NULL)
            return;

        const QLCFixtureDef *def = fixture->fixtureDef();
        if (def == NULL)
            return;

        QString manufacturer = def->manufacturer();
        QString model = def->model();
        int chIdx = item->text(KColumnChIdx).toInt();
        Qt::CheckState enable = item->checkState(KColumnGroup);

        qDebug() << "Manuf:" << manufacturer << ", model:" << model << ", ch:" << chIdx;

        for (int t = 0; t < m_tree->topLevelItemCount(); t++)
        {
            QTreeWidgetItem *uniItem = m_tree->topLevelItem(t);
            for (int f = 0; f < uniItem->childCount(); f++)
            {
                QTreeWidgetItem *fixItem = uniItem->child(f);
                quint32 fxID = fixItem->text(KColumnID).toUInt();
                Fixture *fxi = m_doc->fixture(fxID);
                if (fxi != NULL)
                {
                    const QLCFixtureDef *tmpDef = fxi->fixtureDef();
                    if (tmpDef != NULL)
                    {
                        QString tmpManuf = tmpDef->manufacturer();
                        QString tmpModel = tmpDef->model();
                        if (tmpManuf == manufacturer && tmpModel == model)
                        {
                            QTreeWidgetItem* item = fixItem->child(chIdx);
                            if (item != NULL)
                            {
                                item->setCheckState(KColumnGroup, enable);
                                if (enable == Qt::Checked)
                                    m_checkedChannels++;
                                else
                                    m_checkedChannels--;
                            }
                        }
                    }
                }
            }
        }
    }

    if (m_checkedChannels > 0)
        m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
    else
        m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);

    m_isUpdating = false;
}

void AddChannelsGroup::slotAutoDetectInputToggled(bool checked)
{
    if (checked == true)
    {
        connect(m_doc->inputMap(), SIGNAL(inputValueChanged(quint32,quint32,uchar)),
                this, SLOT(slotInputValueChanged(quint32,quint32)));
    }
    else
    {
        disconnect(m_doc->inputMap(), SIGNAL(inputValueChanged(quint32,quint32,uchar)),
                   this, SLOT(slotInputValueChanged(quint32,quint32)));
    }
}

void AddChannelsGroup::slotInputValueChanged(quint32 universe, quint32 channel)
{
    m_inputSource = QLCInputSource(universe, channel);
    updateInputSource();
}

void AddChannelsGroup::slotChooseInputClicked()
{
    SelectInputChannel sic(this, m_doc->inputMap());
    if (sic.exec() == QDialog::Accepted)
    {
        m_inputSource = QLCInputSource(sic.universe(), sic.channel());
        updateInputSource();
    }
}

void AddChannelsGroup::updateInputSource()
{
    QString uniName;
    QString chName;

    if (m_doc->inputMap()->inputSourceNames(m_inputSource, uniName, chName) == false)
    {
        uniName = KInputNone;
        chName = KInputNone;
    }

    m_inputUniverseEdit->setText(uniName);
    m_inputChannelEdit->setText(chName);
}

<|endoftext|>


<commit_before>/* Copyright (c) 2010-present Advanced Micro Devices, Inc.

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE. */

#ifndef VERSIONS_HPP_
#define VERSIONS_HPP_

#include "utils/macros.hpp"

#ifndef AMD_PLATFORM_NAME
#define AMD_PLATFORM_NAME "AMD Accelerated Parallel Processing"
#endif  // AMD_PLATFORM_NAME

#ifndef AMD_PLATFORM_BUILD_NUMBER
#define AMD_PLATFORM_BUILD_NUMBER 3202
#endif  // AMD_PLATFORM_BUILD_NUMBER

#ifndef AMD_PLATFORM_REVISION_NUMBER
#define AMD_PLATFORM_REVISION_NUMBER 0
#endif  // AMD_PLATFORM_REVISION_NUMBER

#ifndef AMD_PLATFORM_RELEASE_INFO
#define AMD_PLATFORM_RELEASE_INFO
#endif  // AMD_PLATFORM_RELEASE_INFO

#define AMD_BUILD_STRING                                                                           \
  XSTR(AMD_PLATFORM_BUILD_NUMBER)                                                                  \
  "." XSTR(AMD_PLATFORM_REVISION_NUMBER)

#ifndef AMD_PLATFORM_INFO
#define AMD_PLATFORM_INFO                                                                          \
  "AMD-APP" AMD_PLATFORM_RELEASE_INFO DEBUG_ONLY(                                                  \
      "." IF(IS_OPTIMIZED, "opt", "dbg")) " (" AMD_BUILD_STRING ")"
#endif  // ATI_PLATFORM_INFO

#endif  // VERSIONS_HPP_
<commit_msg>SWDEV-2 - Change OpenCL version number from  3202 to 3203<commit_after>/* Copyright (c) 2010-present Advanced Micro Devices, Inc.

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE. */

#ifndef VERSIONS_HPP_
#define VERSIONS_HPP_

#include "utils/macros.hpp"

#ifndef AMD_PLATFORM_NAME
#define AMD_PLATFORM_NAME "AMD Accelerated Parallel Processing"
#endif  // AMD_PLATFORM_NAME

#ifndef AMD_PLATFORM_BUILD_NUMBER
#define AMD_PLATFORM_BUILD_NUMBER 3203
#endif  // AMD_PLATFORM_BUILD_NUMBER

#ifndef AMD_PLATFORM_REVISION_NUMBER
#define AMD_PLATFORM_REVISION_NUMBER 0
#endif  // AMD_PLATFORM_REVISION_NUMBER

#ifndef AMD_PLATFORM_RELEASE_INFO
#define AMD_PLATFORM_RELEASE_INFO
#endif  // AMD_PLATFORM_RELEASE_INFO

#define AMD_BUILD_STRING                                                                           \
  XSTR(AMD_PLATFORM_BUILD_NUMBER)                                                                  \
  "." XSTR(AMD_PLATFORM_REVISION_NUMBER)

#ifndef AMD_PLATFORM_INFO
#define AMD_PLATFORM_INFO                                                                          \
  "AMD-APP" AMD_PLATFORM_RELEASE_INFO DEBUG_ONLY(                                                  \
      "." IF(IS_OPTIMIZED, "opt", "dbg")) " (" AMD_BUILD_STRING ")"
#endif  // ATI_PLATFORM_INFO

#endif  // VERSIONS_HPP_
<|endoftext|>


<commit_before>/*
    Copyright (c) Aleksey Fedotov
    MIT license
*/

#include "VulkanImage.h"
#include "VulkanBuffer.h"
#include "VulkanDevice.h"
#include "../ImageData.h"
#include <vector>

static auto toVulkanFormat(ImageData::Format format) -> VkFormat
{
    switch (format)
    {
        case ImageData::Format::R8G8B8A8_UNORM: return VK_FORMAT_R8G8B8A8_UNORM;
        default:
            KL_PANIC("Unsupported texture format");
            return VK_FORMAT_UNDEFINED;
    }
}

static auto createImage(VkDevice device, VkFormat format, uint32_t width, uint32_t height, uint32_t mipLevels,
    uint32_t arrayLayers, VkImageCreateFlags createFlags, VkImageUsageFlags usageFlags) -> vk::Resource<VkImage>
{
    VkImageCreateInfo imageCreateInfo{};
    imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
    imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
    imageCreateInfo.format = format;
    imageCreateInfo.mipLevels = mipLevels;
    imageCreateInfo.arrayLayers = arrayLayers;
    imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
    imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
    imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
    imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
    imageCreateInfo.extent = {width, height, 1};
    imageCreateInfo.usage = usageFlags;
    imageCreateInfo.flags = createFlags;

    vk::Resource<VkImage> image{device, vkDestroyImage};
    KL_VK_CHECK_RESULT(vkCreateImage(device, &imageCreateInfo, nullptr, image.cleanRef()));

    return image;
}

static auto createSampler(VkDevice device, VkPhysicalDeviceFeatures physicalFeatures, VkPhysicalDeviceProperties physicalProps,
    uint32_t mipLevels) -> vk::Resource<VkSampler>
{
    VkSamplerCreateInfo samplerInfo{};
    samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
    samplerInfo.maxAnisotropy = 1.0f;
    samplerInfo.anisotropyEnable = VK_FALSE;
    samplerInfo.magFilter = VK_FILTER_LINEAR;
    samplerInfo.minFilter = VK_FILTER_LINEAR;
    samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
    samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
    samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
    samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
    samplerInfo.mipLodBias = 0.0f;
    samplerInfo.compareOp = VK_COMPARE_OP_NEVER;
    samplerInfo.minLod = 0.0f;
    samplerInfo.maxLod = mipLevels;
    samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;

    if (physicalFeatures.samplerAnisotropy)
    {
        samplerInfo.maxAnisotropy = physicalProps.limits.maxSamplerAnisotropy;
        samplerInfo.anisotropyEnable = VK_TRUE;
    }

    vk::Resource<VkSampler> sampler{device, vkDestroySampler};
    KL_VK_CHECK_RESULT(vkCreateSampler(device, &samplerInfo, nullptr, sampler.cleanRef()));

    return sampler;
}

static void setImageLayout(VkCommandBuffer cmdbuffer, VkImage image, VkImageLayout oldImageLayout, VkImageLayout newImageLayout,
    VkImageSubresourceRange subresourceRange, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask)
{
    VkImageMemoryBarrier imageMemoryBarrier{};
	imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
	imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
	imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
    imageMemoryBarrier.oldLayout = oldImageLayout;
    imageMemoryBarrier.newLayout = newImageLayout;
    imageMemoryBarrier.image = image;
    imageMemoryBarrier.subresourceRange = subresourceRange;

    // Source layouts (old)
    // Source access mask controls actions that have to be finished on the old layout
    // before it will be transitioned to the new layout
    switch (oldImageLayout)
    {
        case VK_IMAGE_LAYOUT_UNDEFINED:
            // Image layout is undefined (or does not matter)
            // Only valid as initial layout
            // No flags required, listed only for completeness
            imageMemoryBarrier.srcAccessMask = 0;
            break;

        case VK_IMAGE_LAYOUT_PREINITIALIZED:
            // Image is preinitialized
            // Only valid as initial layout for linear images, preserves memory contents
            // Make sure host writes have been finished
            imageMemoryBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
            break;

        case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
            // Image is a color attachment
            // Make sure any writes to the color buffer have been finished
            imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
            break;

        case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
            // Image is a depth/stencil attachment
            // Make sure any writes to the depth/stencil buffer have been finished
            imageMemoryBarrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
            break;

        case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
            // Image is a transfer source
            // Make sure any reads from the image have been finished
            imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
            break;

        case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
            // Image is a transfer destination
            // Make sure any writes to the image have been finished
            imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
            break;

        case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
            // Image is read by a shader
            // Make sure any shader reads from the image have been finished
            imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
            break;
        default:
            break;
    }

    // Target layouts (new)
    // Destination access mask controls the dependency for the new image layout
    switch (newImageLayout)
    {
        case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
            // Image will be used as a transfer destination
            // Make sure any writes to the image have been finished
            imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
            break;

        case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
            // Image will be used as a transfer source
            // Make sure any reads from the image have been finished
            imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
            break;

        case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
            // Image will be used as a color attachment
            // Make sure any writes to the color buffer have been finished
            imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
            break;

        case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
            // Image layout will be used as a depth/stencil attachment
            // Make sure any writes to depth/stencil buffer have been finished
            imageMemoryBarrier.dstAccessMask = imageMemoryBarrier.dstAccessMask | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
            break;

        case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
            // Image will be read in a shader (sampler, input attachment)
            // Make sure any writes to the image have been finished
            if (imageMemoryBarrier.srcAccessMask == 0)
                imageMemoryBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
            imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
            break;
        default:
            break;
    }

    vkCmdPipelineBarrier(cmdbuffer, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
}

static auto allocateImageMemory(VkDevice device, VkPhysicalDeviceMemoryProperties memProps, VkImage image) -> vk::Resource<VkDeviceMemory>
{
    VkMemoryRequirements memReqs{};
    vkGetImageMemoryRequirements(device, image, &memReqs);

    VkMemoryAllocateInfo allocInfo{};
    allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
    allocInfo.allocationSize = memReqs.size;
    allocInfo.memoryTypeIndex = vk::findMemoryType(memProps, memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);

    vk::Resource<VkDeviceMemory> memory{device, vkFreeMemory};
    KL_VK_CHECK_RESULT(vkAllocateMemory(device, &allocInfo, nullptr, memory.cleanRef()));
    KL_VK_CHECK_RESULT(vkBindImageMemory(device, image, memory, 0));

    return memory;
}

auto vk::Image::create2D(const Device &device, const ImageData &data) -> Image
{
    const auto mipLevels = data.getMipLevelCount();
    const auto width = data.getWidth(0);
    const auto height = data.getHeight(0);
    const auto format = toVulkanFormat(data.getFormat());

    auto image = Image(device, width, height, mipLevels, 1, format,
        0,
        VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
        VK_IMAGE_VIEW_TYPE_2D,
        VK_IMAGE_ASPECT_COLOR_BIT);
    image.uploadData(device, data);

    return image;
}

auto vk::Image::createCube(const Device &device, const ImageData &data) -> Image
{
    const auto mipLevels = data.getMipLevelCount();
    const auto width = data.getWidth(0, 0);
    const auto height = data.getHeight(0, 0);
    const auto format = toVulkanFormat(data.getFormat());

    auto image = Image(device, width, height, mipLevels, 6, format,
        VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT,
        VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
        VK_IMAGE_VIEW_TYPE_CUBE,
        VK_IMAGE_ASPECT_COLOR_BIT);
    image.uploadData(device, data);

    return image;
}

vk::Image::Image(const Device &device, uint32_t width, uint32_t height, uint32_t mipLevels, uint32_t layers, VkFormat format,
    VkImageCreateFlags createFlags, VkImageUsageFlags usageFlags, VkImageViewType viewType, VkImageAspectFlags aspectMask):
    mipLevels(mipLevels),
    layers(layers),
    aspectMask(aspectMask)
{
    auto image = createImage(device, format, width, height, mipLevels, layers, createFlags, usageFlags);
    auto memory = allocateImageMemory(device, device.getPhysicalMemoryFeatures(), image);
    auto sampler = createSampler(device, device.getPhysicalFeatures(), device.getPhysicalProperties(), mipLevels);
    auto view = createImageView(device, format, viewType, mipLevels, layers, image, aspectMask);
    this->image = std::move(image);
    this->memory = std::move(memory);
    this->sampler = std::move(sampler);
    this->view = std::move(view);
}

void vk::Image::uploadData(const Device &device, const ImageData &data)
{
    VkImageSubresourceRange subresourceRange{};
	subresourceRange.aspectMask = aspectMask;
	subresourceRange.baseMipLevel = 0;
	subresourceRange.levelCount = mipLevels;
	subresourceRange.layerCount = layers;

    uint32_t offset = 0;
    std::vector<VkBufferImageCopy> copyRegions;
    for (uint32_t layer = 0; layer < layers; layer++)
    {
        for (uint32_t level = 0; level < mipLevels; level++)
        {
            VkBufferImageCopy bufferCopyRegion = {};
            bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
            bufferCopyRegion.imageSubresource.mipLevel = level;
            bufferCopyRegion.imageSubresource.baseArrayLayer = layer;
            bufferCopyRegion.imageSubresource.layerCount = 1;
            bufferCopyRegion.imageExtent.width = data.getWidth(layer, level);
            bufferCopyRegion.imageExtent.height = data.getHeight(layer, level);
            bufferCopyRegion.imageExtent.depth = 1;
            bufferCopyRegion.bufferOffset = offset;

            copyRegions.push_back(bufferCopyRegion);

            offset += data.getSize(layer, level);
        }
    }

    auto srcBuf = Buffer::createStaging(device, data.getSize(), data.getData());

    auto cmdBuf = createCommandBuffer(device, device.getCommandPool());
    beginCommandBuffer(cmdBuf, true);

    setImageLayout(
        cmdBuf,
        image,
        VK_IMAGE_LAYOUT_UNDEFINED,
        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
        subresourceRange,
        VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
        VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);

    vkCmdCopyBufferToImage(
        cmdBuf,
        srcBuf,
        image,
        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
        copyRegions.size(),
        copyRegions.data());

    auto imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
    setImageLayout(
        cmdBuf,
        image,
        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
        imageLayout,
        subresourceRange,
        VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
        VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);

    vkEndCommandBuffer(cmdBuf);

    queueSubmit(device.getQueue(), 0, nullptr, 0, nullptr, 1, &cmdBuf);
    KL_VK_CHECK_RESULT(vkQueueWaitIdle(device.getQueue()));
}
<commit_msg>Cleanup<commit_after>/*
    Copyright (c) Aleksey Fedotov
    MIT license
*/

#include "VulkanImage.h"
#include "VulkanBuffer.h"
#include "VulkanDevice.h"
#include "../ImageData.h"
#include <vector>

static auto toVulkanFormat(ImageData::Format format) -> VkFormat
{
    switch (format)
    {
        case ImageData::Format::R8G8B8A8_UNORM: return VK_FORMAT_R8G8B8A8_UNORM;
        default:
            KL_PANIC("Unsupported texture format");
            return VK_FORMAT_UNDEFINED;
    }
}

static auto createImage(VkDevice device, VkFormat format, uint32_t width, uint32_t height, uint32_t mipLevels,
    uint32_t arrayLayers, VkImageCreateFlags createFlags, VkImageUsageFlags usageFlags) -> vk::Resource<VkImage>
{
    VkImageCreateInfo imageCreateInfo{};
    imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
    imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
    imageCreateInfo.format = format;
    imageCreateInfo.mipLevels = mipLevels;
    imageCreateInfo.arrayLayers = arrayLayers;
    imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
    imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
    imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
    imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
    imageCreateInfo.extent = {width, height, 1};
    imageCreateInfo.usage = usageFlags;
    imageCreateInfo.flags = createFlags;

    vk::Resource<VkImage> image{device, vkDestroyImage};
    KL_VK_CHECK_RESULT(vkCreateImage(device, &imageCreateInfo, nullptr, image.cleanRef()));

    return image;
}

static auto createSampler(VkDevice device, VkPhysicalDeviceFeatures physicalFeatures, VkPhysicalDeviceProperties physicalProps,
    uint32_t mipLevels) -> vk::Resource<VkSampler>
{
    VkSamplerCreateInfo samplerInfo{};
    samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
    samplerInfo.maxAnisotropy = 1.0f;
    samplerInfo.anisotropyEnable = VK_FALSE;
    samplerInfo.magFilter = VK_FILTER_LINEAR;
    samplerInfo.minFilter = VK_FILTER_LINEAR;
    samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
    samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
    samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
    samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
    samplerInfo.mipLodBias = 0.0f;
    samplerInfo.compareOp = VK_COMPARE_OP_NEVER;
    samplerInfo.minLod = 0.0f;
    samplerInfo.maxLod = mipLevels;
    samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;

    if (physicalFeatures.samplerAnisotropy)
    {
        samplerInfo.maxAnisotropy = physicalProps.limits.maxSamplerAnisotropy;
        samplerInfo.anisotropyEnable = VK_TRUE;
    }

    vk::Resource<VkSampler> sampler{device, vkDestroySampler};
    KL_VK_CHECK_RESULT(vkCreateSampler(device, &samplerInfo, nullptr, sampler.cleanRef()));

    return sampler;
}

static void setImageLayout(VkCommandBuffer cmdbuffer, VkImage image, VkImageLayout oldImageLayout, VkImageLayout newImageLayout,
    VkImageSubresourceRange subresourceRange, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask)
{
    VkImageMemoryBarrier imageMemoryBarrier{};
	imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
	imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
	imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
    imageMemoryBarrier.oldLayout = oldImageLayout;
    imageMemoryBarrier.newLayout = newImageLayout;
    imageMemoryBarrier.image = image;
    imageMemoryBarrier.subresourceRange = subresourceRange;

    // Source layouts (old)
    // Source access mask controls actions that have to be finished on the old layout
    // before it will be transitioned to the new layout
    switch (oldImageLayout)
    {
        case VK_IMAGE_LAYOUT_UNDEFINED:
            // Image layout is undefined (or does not matter)
            // Only valid as initial layout
            // No flags required, listed only for completeness
            imageMemoryBarrier.srcAccessMask = 0;
            break;

        case VK_IMAGE_LAYOUT_PREINITIALIZED:
            // Image is preinitialized
            // Only valid as initial layout for linear images, preserves memory contents
            // Make sure host writes have been finished
            imageMemoryBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
            break;

        case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
            // Image is a color attachment
            // Make sure any writes to the color buffer have been finished
            imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
            break;

        case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
            // Image is a depth/stencil attachment
            // Make sure any writes to the depth/stencil buffer have been finished
            imageMemoryBarrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
            break;

        case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
            // Image is a transfer source
            // Make sure any reads from the image have been finished
            imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
            break;

        case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
            // Image is a transfer destination
            // Make sure any writes to the image have been finished
            imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
            break;

        case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
            // Image is read by a shader
            // Make sure any shader reads from the image have been finished
            imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
            break;
        default:
            break;
    }

    // Target layouts (new)
    // Destination access mask controls the dependency for the new image layout
    switch (newImageLayout)
    {
        case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
            // Image will be used as a transfer destination
            // Make sure any writes to the image have been finished
            imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
            break;

        case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
            // Image will be used as a transfer source
            // Make sure any reads from the image have been finished
            imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
            break;

        case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
            // Image will be used as a color attachment
            // Make sure any writes to the color buffer have been finished
            imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
            break;

        case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
            // Image layout will be used as a depth/stencil attachment
            // Make sure any writes to depth/stencil buffer have been finished
            imageMemoryBarrier.dstAccessMask = imageMemoryBarrier.dstAccessMask | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
            break;

        case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
            // Image will be read in a shader (sampler, input attachment)
            // Make sure any writes to the image have been finished
            if (imageMemoryBarrier.srcAccessMask == 0)
                imageMemoryBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
            imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
            break;
        default:
            break;
    }

    vkCmdPipelineBarrier(cmdbuffer, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
}

static auto allocateImageMemory(VkDevice device, VkPhysicalDeviceMemoryProperties memProps, VkImage image) -> vk::Resource<VkDeviceMemory>
{
    VkMemoryRequirements memReqs{};
    vkGetImageMemoryRequirements(device, image, &memReqs);

    VkMemoryAllocateInfo allocInfo{};
    allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
    allocInfo.allocationSize = memReqs.size;
    allocInfo.memoryTypeIndex = vk::findMemoryType(memProps, memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);

    vk::Resource<VkDeviceMemory> memory{device, vkFreeMemory};
    KL_VK_CHECK_RESULT(vkAllocateMemory(device, &allocInfo, nullptr, memory.cleanRef()));
    KL_VK_CHECK_RESULT(vkBindImageMemory(device, image, memory, 0));

    return memory;
}

auto vk::Image::create2D(const Device &device, const ImageData &data) -> Image
{
    const auto mipLevels = data.getMipLevelCount();
    const auto width = data.getWidth(0);
    const auto height = data.getHeight(0);
    const auto format = toVulkanFormat(data.getFormat());

    auto image = Image(device, width, height, mipLevels, 1, format,
        0,
        VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
        VK_IMAGE_VIEW_TYPE_2D,
        VK_IMAGE_ASPECT_COLOR_BIT);
    image.uploadData(device, data);

    return image;
}

auto vk::Image::createCube(const Device &device, const ImageData &data) -> Image
{
    const auto mipLevels = data.getMipLevelCount();
    const auto width = data.getWidth(0, 0);
    const auto height = data.getHeight(0, 0);
    const auto format = toVulkanFormat(data.getFormat());

    auto image = Image(device, width, height, mipLevels, 6, format,
        VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT,
        VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
        VK_IMAGE_VIEW_TYPE_CUBE,
        VK_IMAGE_ASPECT_COLOR_BIT);
    image.uploadData(device, data);

    return image;
}

vk::Image::Image(const Device &device, uint32_t width, uint32_t height, uint32_t mipLevels, uint32_t layers, VkFormat format,
    VkImageCreateFlags createFlags, VkImageUsageFlags usageFlags, VkImageViewType viewType, VkImageAspectFlags aspectMask):
    mipLevels(mipLevels),
    layers(layers),
    aspectMask(aspectMask)
{
    auto image = createImage(device, format, width, height, mipLevels, layers, createFlags, usageFlags);
    auto memory = allocateImageMemory(device, device.getPhysicalMemoryFeatures(), image);
    auto sampler = createSampler(device, device.getPhysicalFeatures(), device.getPhysicalProperties(), mipLevels);
    auto view = createImageView(device, format, viewType, mipLevels, layers, image, aspectMask);
    this->image = std::move(image);
    this->memory = std::move(memory);
    this->sampler = std::move(sampler);
    this->view = std::move(view);
}

void vk::Image::uploadData(const Device &device, const ImageData &data)
{
    uint32_t offset = 0;
    std::vector<VkBufferImageCopy> copyRegions;
    for (uint32_t layer = 0; layer < layers; layer++)
    {
        for (uint32_t level = 0; level < mipLevels; level++)
        {
            VkBufferImageCopy bufferCopyRegion = {};
            bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
            bufferCopyRegion.imageSubresource.mipLevel = level;
            bufferCopyRegion.imageSubresource.baseArrayLayer = layer;
            bufferCopyRegion.imageSubresource.layerCount = 1;
            bufferCopyRegion.imageExtent.width = data.getWidth(layer, level);
            bufferCopyRegion.imageExtent.height = data.getHeight(layer, level);
            bufferCopyRegion.imageExtent.depth = 1;
            bufferCopyRegion.bufferOffset = offset;

            copyRegions.push_back(bufferCopyRegion);

            offset += data.getSize(layer, level);
        }
    }

    VkImageSubresourceRange subresourceRange{};
	subresourceRange.aspectMask = aspectMask;
	subresourceRange.baseMipLevel = 0;
	subresourceRange.levelCount = mipLevels;
	subresourceRange.layerCount = layers;

    auto srcBuf = Buffer::createStaging(device, data.getSize(), data.getData());

    auto cmdBuf = createCommandBuffer(device, device.getCommandPool());
    beginCommandBuffer(cmdBuf, true);

    setImageLayout(
        cmdBuf,
        image,
        VK_IMAGE_LAYOUT_UNDEFINED,
        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
        subresourceRange,
        VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
        VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);

    vkCmdCopyBufferToImage(
        cmdBuf,
        srcBuf,
        image,
        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
        copyRegions.size(),
        copyRegions.data());

    auto imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
    setImageLayout(
        cmdBuf,
        image,
        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
        imageLayout,
        subresourceRange,
        VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
        VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);

    vkEndCommandBuffer(cmdBuf);

    queueSubmit(device.getQueue(), 0, nullptr, 0, nullptr, 1, &cmdBuf);
    KL_VK_CHECK_RESULT(vkQueueWaitIdle(device.getQueue()));
}
<|endoftext|>


<commit_before>#include "XSCommon/XSCommon.h"
#include "XSCommon/XSFile.h"
#include "XSCommon/XSConsole.h"
#include "XSCommon/XSCvar.h"
#include "XSClient/XSClientGame.h"
#include "XSClient/XSGameObject.h"
#include "XSClient/XSTerrain.h"
#include "XSClient/XSPerlin.h"
#include "XSRenderer/XSRenderer.h"
#include "XSRenderer/XSShaderProgram.h"
#include "XSRenderer/XSMaterial.h"
#include "XSRenderer/XSTexture.h"
#include "XSRenderer/XSModel.h"
#include "XSRenderer/XSMesh.h"
#include "XSRenderer/XSVertexAttributes.h"
#include "XSRenderer/XSImagePNG.h"

namespace XS {

	namespace ClientGame {

		Cvar *cg_terrainPersistence = nullptr;
		Cvar *cg_terrainFrequency = nullptr;
		Cvar *cg_terrainAmplitude = nullptr;
		Cvar *cg_terrainOctaves = nullptr;
		Cvar *cg_terrainDimensions = nullptr;

		static uint8_t GetHeight( const uint8_t *data, size_t size, size_t row, size_t col ) {
			return data[(row * size) + col];
		}

		Terrain::Terrain( const char *path ) {

			const size_t dimensions = cg_terrainDimensions->GetUInt32();

			Perlin perlin(
				cg_terrainPersistence->GetReal64(), // persistence
				cg_terrainFrequency->GetReal64(), // frequency
				cg_terrainAmplitude->GetReal64(), // amplitude
				cg_terrainOctaves->GetInt32(), // octaves
				rand() // seed
			);

			uint8_t *heightmap = new uint8_t[dimensions * dimensions];
			std::memset( heightmap, 0, dimensions * dimensions );
			for ( int row = 0; row < dimensions; row++ ) {
				for ( int col = 0; col < dimensions; col++ ) {
					real64_t p = perlin.GetHeight( row, col ); // [-1.0, 1.0]
					real64_t r = (p + 1.0) / 2.0; // [0.0, 1.0]
					heightmap[(row * dimensions) + col] = static_cast<uint8_t>( r * 128.0 );
				}
			}

			gameObj = new GameObject();
			gameObj->renderObject = Renderer::Model::Register( nullptr );
			Renderer::Mesh *mesh = new Renderer::Mesh();
			const real32_t scale = 128.0f;

			// positions
			mesh->vertices.reserve( dimensions * dimensions );
			for ( int row = 0; row < dimensions; row++ ) {
				const float fRow = static_cast<real32_t>( row );
				for ( int col = 0; col < dimensions; col++ ) {
					const float fCol = static_cast<real32_t>( col );
					const uint8_t *sample = &heightmap[(row * dimensions) + col];
					vector3 pos;
					pos.x = -fRow;
					pos.y = (static_cast<real32_t>( *sample ) / 255.0f) * scale;
					pos.z = -fCol;
					mesh->vertices.push_back( pos );

					vector2 uv;
					uv.x = fCol / dimensions;
					uv.y = fRow / dimensions;
					mesh->UVs.push_back( uv );
				}
			}

			delete[] heightmap;

			// normals
			mesh->normals.reserve( dimensions * dimensions );
			for ( int row = 0; row < dimensions; row++ ) {
				for ( int col = 0; col < dimensions; col++ ) {
					//TODO: handle edge cases more gracefully
					vector3 normal;
					if ( row != dimensions - 1 && col != dimensions - 1 ) {
						vector3 a = mesh->vertices[row * dimensions + col];
						vector3 b = vector3( mesh->vertices[(row + 1) * dimensions + col] );
						vector3 d = vector3( mesh->vertices[(row + 1) * dimensions + (col + 1)] );
						normal = vector3::cross( b - a, d - a );
					}
					normal.normaliseFast();
					mesh->normals.push_back( normal );
				}
			}

			// indices
			mesh->indices.reserve( (dimensions - 1) * (dimensions - 1) * 6 );
			for ( int row = 0; row < dimensions - 1; row++ ) {
				for ( int col = 0; col < dimensions - 1; col++ ) {
					const int32_t start = (row * dimensions) + col;
					mesh->indices.push_back( start );
					mesh->indices.push_back( start + 1 );
					mesh->indices.push_back( start + dimensions );

					mesh->indices.push_back( start + 1 );
					mesh->indices.push_back( start + 1 + dimensions );
					mesh->indices.push_back( start + dimensions );
				}
			}

			mesh->Upload();

			dynamic_cast<Renderer::Model *>( gameObj->renderObject )->meshes.push_back( mesh );
			AddObject( gameObj );

			// create texture
			uint32_t outWidth = 0u, outHeight = 0u;
			uint8_t *dirtData = Renderer::LoadPNG( "textures/dirt.png", &outWidth, &outHeight );
			texture = new Renderer::Texture( outWidth, outHeight, Renderer::InternalFormat::RGBA8, dirtData );
			delete dirtData;

			// create shader program
			static const Renderer::VertexAttribute attributes[] = {
				{ 0, "in_Position" },
				{ 1, "in_Normal" },
				{ 2, "in_TexCoord" },
			};
			program = new Renderer::ShaderProgram( "model", "model", attributes, ARRAY_LEN( attributes ) );

			// create material
			material = new Renderer::Material();
			Renderer::Material::SamplerBinding samplerBinding;
			samplerBinding.unit = 0;
			samplerBinding.texture = texture;
			material->samplerBindings.push_back( samplerBinding );
			material->shaderProgram = program;
			//terrainMaterial->flags |= Renderer::MF_WIREFRAME;

			mesh->material = material;
		}

		Terrain::~Terrain() {
			RemoveObject( gameObj );
			delete gameObj;
			delete program;
			delete texture;
		}

	} // namespace ClientGame

} // namespace XS
<commit_msg>Remove unused function GetHeight<commit_after>#include "XSCommon/XSCommon.h"
#include "XSCommon/XSFile.h"
#include "XSCommon/XSConsole.h"
#include "XSCommon/XSCvar.h"
#include "XSClient/XSClientGame.h"
#include "XSClient/XSGameObject.h"
#include "XSClient/XSTerrain.h"
#include "XSClient/XSPerlin.h"
#include "XSRenderer/XSRenderer.h"
#include "XSRenderer/XSShaderProgram.h"
#include "XSRenderer/XSMaterial.h"
#include "XSRenderer/XSTexture.h"
#include "XSRenderer/XSModel.h"
#include "XSRenderer/XSMesh.h"
#include "XSRenderer/XSVertexAttributes.h"
#include "XSRenderer/XSImagePNG.h"

namespace XS {

	namespace ClientGame {

		Cvar *cg_terrainPersistence = nullptr;
		Cvar *cg_terrainFrequency = nullptr;
		Cvar *cg_terrainAmplitude = nullptr;
		Cvar *cg_terrainOctaves = nullptr;
		Cvar *cg_terrainDimensions = nullptr;

		Terrain::Terrain( const char *path ) {

			const size_t dimensions = cg_terrainDimensions->GetUInt32();

			Perlin perlin(
				cg_terrainPersistence->GetReal64(), // persistence
				cg_terrainFrequency->GetReal64(), // frequency
				cg_terrainAmplitude->GetReal64(), // amplitude
				cg_terrainOctaves->GetInt32(), // octaves
				rand() // seed
			);

			uint8_t *heightmap = new uint8_t[dimensions * dimensions];
			std::memset( heightmap, 0, dimensions * dimensions );
			for ( int row = 0; row < dimensions; row++ ) {
				for ( int col = 0; col < dimensions; col++ ) {
					real64_t p = perlin.GetHeight( row, col ); // [-1.0, 1.0]
					real64_t r = (p + 1.0) / 2.0; // [0.0, 1.0]
					heightmap[(row * dimensions) + col] = static_cast<uint8_t>( r * 128.0 );
				}
			}

			gameObj = new GameObject();
			gameObj->renderObject = Renderer::Model::Register( nullptr );
			Renderer::Mesh *mesh = new Renderer::Mesh();
			const real32_t scale = 128.0f;

			// positions
			mesh->vertices.reserve( dimensions * dimensions );
			for ( int row = 0; row < dimensions; row++ ) {
				const float fRow = static_cast<real32_t>( row );
				for ( int col = 0; col < dimensions; col++ ) {
					const float fCol = static_cast<real32_t>( col );
					const uint8_t *sample = &heightmap[(row * dimensions) + col];
					vector3 pos;
					pos.x = -fRow;
					pos.y = (static_cast<real32_t>( *sample ) / 255.0f) * scale;
					pos.z = -fCol;
					mesh->vertices.push_back( pos );

					vector2 uv;
					uv.x = fCol / dimensions;
					uv.y = fRow / dimensions;
					mesh->UVs.push_back( uv );
				}
			}

			delete[] heightmap;

			// normals
			mesh->normals.reserve( dimensions * dimensions );
			for ( int row = 0; row < dimensions; row++ ) {
				for ( int col = 0; col < dimensions; col++ ) {
					//TODO: handle edge cases more gracefully
					vector3 normal;
					if ( row != dimensions - 1 && col != dimensions - 1 ) {
						vector3 a = mesh->vertices[row * dimensions + col];
						vector3 b = vector3( mesh->vertices[(row + 1) * dimensions + col] );
						vector3 d = vector3( mesh->vertices[(row + 1) * dimensions + (col + 1)] );
						normal = vector3::cross( b - a, d - a );
					}
					normal.normaliseFast();
					mesh->normals.push_back( normal );
				}
			}

			// indices
			mesh->indices.reserve( (dimensions - 1) * (dimensions - 1) * 6 );
			for ( int row = 0; row < dimensions - 1; row++ ) {
				for ( int col = 0; col < dimensions - 1; col++ ) {
					const int32_t start = (row * dimensions) + col;
					mesh->indices.push_back( start );
					mesh->indices.push_back( start + 1 );
					mesh->indices.push_back( start + dimensions );

					mesh->indices.push_back( start + 1 );
					mesh->indices.push_back( start + 1 + dimensions );
					mesh->indices.push_back( start + dimensions );
				}
			}

			mesh->Upload();

			dynamic_cast<Renderer::Model *>( gameObj->renderObject )->meshes.push_back( mesh );
			AddObject( gameObj );

			// create texture
			uint32_t outWidth = 0u, outHeight = 0u;
			uint8_t *dirtData = Renderer::LoadPNG( "textures/dirt.png", &outWidth, &outHeight );
			texture = new Renderer::Texture( outWidth, outHeight, Renderer::InternalFormat::RGBA8, dirtData );
			delete dirtData;

			// create shader program
			static const Renderer::VertexAttribute attributes[] = {
				{ 0, "in_Position" },
				{ 1, "in_Normal" },
				{ 2, "in_TexCoord" },
			};
			program = new Renderer::ShaderProgram( "model", "model", attributes, ARRAY_LEN( attributes ) );

			// create material
			material = new Renderer::Material();
			Renderer::Material::SamplerBinding samplerBinding;
			samplerBinding.unit = 0;
			samplerBinding.texture = texture;
			material->samplerBindings.push_back( samplerBinding );
			material->shaderProgram = program;
			//terrainMaterial->flags |= Renderer::MF_WIREFRAME;

			mesh->material = material;
		}

		Terrain::~Terrain() {
			RemoveObject( gameObj );
			delete gameObj;
			delete program;
			delete texture;
		}

	} // namespace ClientGame

} // namespace XS
<|endoftext|>


<commit_before>/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:

/*
COPYING CONDITIONS NOTICE:

  This program is free software; you can redistribute it and/or modify
  it under the terms of version 2 of the GNU General Public License as
  published by the Free Software Foundation, and provided that the
  following conditions are met:

      * Redistributions of source code must retain this COPYING
        CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
        DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
        PATENT MARKING NOTICE (below), and the PATENT RIGHTS
        GRANT (below).

      * Redistributions in binary form must reproduce this COPYING
        CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
        DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
        PATENT MARKING NOTICE (below), and the PATENT RIGHTS
        GRANT (below) in the documentation and/or other materials
        provided with the distribution.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  02110-1301, USA.

COPYRIGHT NOTICE:

  TokuDB, Tokutek Fractal Tree Indexing Library.
  Copyright (C) 2007-2013 Tokutek, Inc.

DISCLAIMER:

  This program is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  General Public License for more details.

UNIVERSITY PATENT NOTICE:

  The technology is licensed by the Massachusetts Institute of
  Technology, Rutgers State University of New Jersey, and the Research
  Foundation of State University of New York at Stony Brook under
  United States of America Serial No. 11/760379 and to the patents
  and/or patent applications resulting from it.

PATENT MARKING NOTICE:

  This software is covered by US Patent No. 8,185,551.
  This software is covered by US Patent No. 8,489,638.

PATENT RIGHTS GRANT:

  "THIS IMPLEMENTATION" means the copyrightable works distributed by
  Tokutek as part of the Fractal Tree project.

  "PATENT CLAIMS" means the claims of patents that are owned or
  licensable by Tokutek, both currently or in the future; and that in
  the absence of this license would be infringed by THIS
  IMPLEMENTATION or by using or running THIS IMPLEMENTATION.

  "PATENT CHALLENGE" shall mean a challenge to the validity,
  patentability, enforceability and/or non-infringement of any of the
  PATENT CLAIMS or otherwise opposing any of the PATENT CLAIMS.

  Tokutek hereby grants to you, for the term and geographical scope of
  the PATENT CLAIMS, a non-exclusive, no-charge, royalty-free,
  irrevocable (except as stated in this section) patent license to
  make, have made, use, offer to sell, sell, import, transfer, and
  otherwise run, modify, and propagate the contents of THIS
  IMPLEMENTATION, where such license applies only to the PATENT
  CLAIMS.  This grant does not include claims that would be infringed
  only as a consequence of further modifications of THIS
  IMPLEMENTATION.  If you or your agent or licensee institute or order
  or agree to the institution of patent litigation against any entity
  (including a cross-claim or counterclaim in a lawsuit) alleging that
  THIS IMPLEMENTATION constitutes direct or contributory patent
  infringement, or inducement of patent infringement, then any rights
  granted to you under this License shall terminate as of the date
  such litigation is filed.  If you or your agent or exclusive
  licensee institute or order or agree to the institution of a PATENT
  CHALLENGE, then Tokutek may terminate any rights granted to you
  under this License.
*/

#include <string.h>

#include "portability/toku_assert.h"

#include "util/memarena.h"

class memarena_unit_test {
private:
    static const int magic = 37;

    template <typename F>
    void iterate_chunks(memarena *ma, F &fn) {
        for (memarena::chunk_iterator it(ma); it.more(); it.next()) {
            size_t used = 0;
            const void *buf = it.current(&used);
            fn(buf, used);
        }
    }

    void test_create(size_t size) {
        memarena ma;
        ma.create(size);
        invariant(ma._current_chunk.size == size);
        invariant(ma._current_chunk.used == 0);
        if (size == 0) {
            invariant_null(ma._current_chunk.buf);
        } else {
            invariant_notnull(ma._current_chunk.buf);
        }

        // make sure memory was allocated ok by
        // writing to buf and reading it back
        memset(ma._current_chunk.buf, magic, size);
        for (size_t i = 0; i < size; i++) {
            const char *buf = reinterpret_cast<char *>(ma._current_chunk.buf);
            invariant(buf[i] == magic);
        }
        ma.destroy();
    }

    void test_malloc(size_t size) {
        memarena ma;
        ma.create(14);
        void *v = ma.malloc_from_arena(size);
        invariant_notnull(v);

        // make sure memory was allocated ok by
        // writing to buf and reading it back
        memset(ma._current_chunk.buf, magic, size);
        for (size_t i = 0; i < size; i++) {
            const char *c = reinterpret_cast<char *>(ma._current_chunk.buf);
            invariant(c[i] == magic);
        }
        ma.destroy();
    }

    static void test_iterate_fn(const void *buf, size_t used) {
        for (size_t i = 0; i < used; i++) {
            const char *c = reinterpret_cast<const char *>(buf);
            invariant(c[i] == (char) ((intptr_t) &c[i]));
        }
    }

    void test_iterate(size_t size) {
        memarena ma;
        ma.create(14);
        for (size_t k = 0; k < size / 64; k += 64) {
            void *v = ma.malloc_from_arena(64);
            for (size_t i = 0; i < 64; i++) {
                char *c = reinterpret_cast<char *>(v);
                c[i] = (char) ((intptr_t) &c[i]);
            }
        }
        size_t rest = size % 64;
        if (rest != 0) {
            void *v = ma.malloc_from_arena(64);
            for (size_t i = 0; i < 64; i++) {
                char *c = reinterpret_cast<char *>(v);
                c[i] = (char) ((intptr_t) &c[i]);
            }
        }

        iterate_chunks(&ma, test_iterate_fn);
        ma.destroy();
    }

    void test_move_memory(size_t size) {
        memarena ma;
        ma.create(14);
        for (size_t k = 0; k < size / 64; k += 64) {
            void *v = ma.malloc_from_arena(64);
            for (size_t i = 0; i < 64; i++) {
                char *c = reinterpret_cast<char *>(v);
                c[i] = (char) ((intptr_t) &c[i]);
            }
        }
        size_t rest = size % 64;
        if (rest != 0) {
            void *v = ma.malloc_from_arena(64);
            for (size_t i = 0; i < 64; i++) {
                char *c = reinterpret_cast<char *>(v);
                c[i] = (char) ((intptr_t) &c[i]);
            }
        }

        memarena ma2;
        ma.move_memory(&ma2);
        iterate_chunks(&ma2, test_iterate_fn);

        ma.destroy();
        ma2.destroy();
    }

public:
    void test() {
        test_create(0);
        test_create(64);
        test_create(128 * 1024 * 1024);
        test_malloc(0);
        test_malloc(63);
        test_malloc(64);
        test_malloc(64 * 1024 * 1024);
        test_malloc((64 * 1024 * 1024) + 1);
        test_iterate(0);
        test_iterate(63);
        test_iterate(128 * 1024);
        test_iterate(64 * 1024 * 1024);
        test_iterate((64 * 1024 * 1024) + 1);
        test_move_memory(0);
        test_move_memory(1);
        test_move_memory(63);
        test_move_memory(65);
        test_move_memory(65 * 1024 * 1024);
        test_move_memory(101 * 1024 * 1024);
    }
};

int main(void) {
    memarena_unit_test test;
    test.test();
    return 0;
}
<commit_msg>FT-259 Placate the build slaves with their exotic toolchain.<commit_after>/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:

/*
COPYING CONDITIONS NOTICE:

  This program is free software; you can redistribute it and/or modify
  it under the terms of version 2 of the GNU General Public License as
  published by the Free Software Foundation, and provided that the
  following conditions are met:

      * Redistributions of source code must retain this COPYING
        CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
        DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
        PATENT MARKING NOTICE (below), and the PATENT RIGHTS
        GRANT (below).

      * Redistributions in binary form must reproduce this COPYING
        CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
        DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
        PATENT MARKING NOTICE (below), and the PATENT RIGHTS
        GRANT (below) in the documentation and/or other materials
        provided with the distribution.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  02110-1301, USA.

COPYRIGHT NOTICE:

  TokuDB, Tokutek Fractal Tree Indexing Library.
  Copyright (C) 2007-2013 Tokutek, Inc.

DISCLAIMER:

  This program is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  General Public License for more details.

UNIVERSITY PATENT NOTICE:

  The technology is licensed by the Massachusetts Institute of
  Technology, Rutgers State University of New Jersey, and the Research
  Foundation of State University of New York at Stony Brook under
  United States of America Serial No. 11/760379 and to the patents
  and/or patent applications resulting from it.

PATENT MARKING NOTICE:

  This software is covered by US Patent No. 8,185,551.
  This software is covered by US Patent No. 8,489,638.

PATENT RIGHTS GRANT:

  "THIS IMPLEMENTATION" means the copyrightable works distributed by
  Tokutek as part of the Fractal Tree project.

  "PATENT CLAIMS" means the claims of patents that are owned or
  licensable by Tokutek, both currently or in the future; and that in
  the absence of this license would be infringed by THIS
  IMPLEMENTATION or by using or running THIS IMPLEMENTATION.

  "PATENT CHALLENGE" shall mean a challenge to the validity,
  patentability, enforceability and/or non-infringement of any of the
  PATENT CLAIMS or otherwise opposing any of the PATENT CLAIMS.

  Tokutek hereby grants to you, for the term and geographical scope of
  the PATENT CLAIMS, a non-exclusive, no-charge, royalty-free,
  irrevocable (except as stated in this section) patent license to
  make, have made, use, offer to sell, sell, import, transfer, and
  otherwise run, modify, and propagate the contents of THIS
  IMPLEMENTATION, where such license applies only to the PATENT
  CLAIMS.  This grant does not include claims that would be infringed
  only as a consequence of further modifications of THIS
  IMPLEMENTATION.  If you or your agent or licensee institute or order
  or agree to the institution of patent litigation against any entity
  (including a cross-claim or counterclaim in a lawsuit) alleging that
  THIS IMPLEMENTATION constitutes direct or contributory patent
  infringement, or inducement of patent infringement, then any rights
  granted to you under this License shall terminate as of the date
  such litigation is filed.  If you or your agent or exclusive
  licensee institute or order or agree to the institution of a PATENT
  CHALLENGE, then Tokutek may terminate any rights granted to you
  under this License.
*/

#include <string.h>

#include "portability/toku_assert.h"

#include "util/memarena.h"

class memarena_unit_test {
private:
    static const int magic = 37;

    template <typename F>
    void iterate_chunks(memarena *ma, F &fn) {
        for (memarena::chunk_iterator it(ma); it.more(); it.next()) {
            size_t used = 0;
            const void *buf = it.current(&used);
            fn(buf, used);
        }
    }

    void test_create(size_t size) {
        memarena ma;
        ma.create(size);
        invariant(ma._current_chunk.size == size);
        invariant(ma._current_chunk.used == 0);
        if (size == 0) {
            invariant_null(ma._current_chunk.buf);
        } else {
            invariant_notnull(ma._current_chunk.buf);
        }

        // make sure memory was allocated ok by
        // writing to buf and reading it back
        if (size > 0) {
            memset(ma._current_chunk.buf, magic, size);
        }
        for (size_t i = 0; i < size; i++) {
            const char *buf = reinterpret_cast<char *>(ma._current_chunk.buf);
            invariant(buf[i] == magic);
        }
        ma.destroy();
    }

    void test_malloc(size_t size) {
        memarena ma;
        ma.create(14);
        void *v = ma.malloc_from_arena(size);
        invariant_notnull(v);

        // make sure memory was allocated ok by
        // writing to buf and reading it back
        if (size > 0) {
            memset(ma._current_chunk.buf, magic, size);
        }
        for (size_t i = 0; i < size; i++) {
            const char *c = reinterpret_cast<char *>(ma._current_chunk.buf);
            invariant(c[i] == magic);
        }
        ma.destroy();
    }

    static void test_iterate_fn(const void *buf, size_t used) {
        for (size_t i = 0; i < used; i++) {
            const char *c = reinterpret_cast<const char *>(buf);
            invariant(c[i] == (char) ((intptr_t) &c[i]));
        }
    }

    void test_iterate(size_t size) {
        memarena ma;
        ma.create(14);
        for (size_t k = 0; k < size / 64; k += 64) {
            void *v = ma.malloc_from_arena(64);
            for (size_t i = 0; i < 64; i++) {
                char *c = reinterpret_cast<char *>(v);
                c[i] = (char) ((intptr_t) &c[i]);
            }
        }
        size_t rest = size % 64;
        if (rest != 0) {
            void *v = ma.malloc_from_arena(64);
            for (size_t i = 0; i < 64; i++) {
                char *c = reinterpret_cast<char *>(v);
                c[i] = (char) ((intptr_t) &c[i]);
            }
        }

        iterate_chunks(&ma, test_iterate_fn);
        ma.destroy();
    }

    void test_move_memory(size_t size) {
        memarena ma;
        ma.create(14);
        for (size_t k = 0; k < size / 64; k += 64) {
            void *v = ma.malloc_from_arena(64);
            for (size_t i = 0; i < 64; i++) {
                char *c = reinterpret_cast<char *>(v);
                c[i] = (char) ((intptr_t) &c[i]);
            }
        }
        size_t rest = size % 64;
        if (rest != 0) {
            void *v = ma.malloc_from_arena(64);
            for (size_t i = 0; i < 64; i++) {
                char *c = reinterpret_cast<char *>(v);
                c[i] = (char) ((intptr_t) &c[i]);
            }
        }

        memarena ma2;
        ma.move_memory(&ma2);
        iterate_chunks(&ma2, test_iterate_fn);

        ma.destroy();
        ma2.destroy();
    }

public:
    void test() {
        test_create(0);
        test_create(64);
        test_create(128 * 1024 * 1024);
        test_malloc(0);
        test_malloc(63);
        test_malloc(64);
        test_malloc(64 * 1024 * 1024);
        test_malloc((64 * 1024 * 1024) + 1);
        test_iterate(0);
        test_iterate(63);
        test_iterate(128 * 1024);
        test_iterate(64 * 1024 * 1024);
        test_iterate((64 * 1024 * 1024) + 1);
        test_move_memory(0);
        test_move_memory(1);
        test_move_memory(63);
        test_move_memory(65);
        test_move_memory(65 * 1024 * 1024);
        test_move_memory(101 * 1024 * 1024);
    }
};

int main(void) {
    memarena_unit_test test;
    test.test();
    return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

int N;
int p[200010];
vector<int> V[200010];
bool visited[200010];
bool isloop[200010];
int memo[200010];

int calc(int v) {
  if (memo[v] != -1) return memo[v];
  set<int> S;
  for (auto x : V[v]) {
    S.insert(calc(x));
  }
  for (auto i = 0; ; ++i) {
    if (S.find(i) == S.end()) {
      return (memo[v] = i);
    }
  }
}

int main () {
  cin >> N;
  for (auto i = 0; i < N; ++i) {
    cin >> p[i];
    p[i]--;
  }
  for (auto i = 0; i < N; ++i) {
    V[p[i]].push_back(i);
  }
  fill(visited, visited+200010, false);
  int now = 0;
  while (!visited[now]) {
    visited[now] = true;
    now = p[now];
  }
  fill(isloop, isloop+200010, false);
  while (!isloop[now]) {
    // cerr << "loop: " << now << endl;
    isloop[now] = true;
    now = p[now];
  }
  // cerr << "now = " << now << endl;
  fill(memo, memo+200010, -1);
  for (auto i = 0; i < N; ++i) {
    if (!isloop[i]) {
      calc(i);
      // cerr << "calc(" << i << ") = " << calc(i) << endl;
    }
  }
  vector<int> kouho;
  set<int> S;
  for (auto x : V[now]) {
    if (!isloop[x]) {
      // cerr << "x = " << x << endl;
      S.insert(calc(x));
    }
  }
  for (auto i = 0; ; ++i) {
    if (S.find(i) == S.end()) {
      kouho.push_back(i);
      if (kouho.size() == 2) break;
    }
  }
  /*
  cerr << "kouho: ";
  for (auto x : kouho) {
    cerr << x << " ";
  }
  cerr << endl;
  */
  for (auto z : kouho) {
    for (auto i = 0; i < N; ++i) {
      if (isloop[i]) memo[now] = -1;
    }
    memo[now] = z;
    for (auto x : V[now]) {
      if (isloop[x]) calc(x);
    }
    for (auto i = 0; i < N; ++i) {
      if (isloop[i]) {
        cerr << "calc(" << i << ") = " << calc(i) << endl;
      }
    }
    memo[now] = -1;
    cerr << calc(now) << " " << z << endl;
    if (calc(now) == z) {
      cout << "POSSIBLE" << endl;
      return 0;
    }
  }
  cout << "IMPOSSIBLE" << endl;
}
<commit_msg>submit F.cpp to 'F - Namori Grundy' (arc079) [C++14 (GCC 5.4.1)]<commit_after>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

int N;
int p[200010];
vector<int> V[200010];
bool visited[200010];
bool isloop[200010];
int memo[200010];

int calc(int v) {
  if (memo[v] != -1) return memo[v];
  set<int> S;
  for (auto x : V[v]) {
    S.insert(calc(x));
  }
  for (auto i = 0; ; ++i) {
    if (S.find(i) == S.end()) {
      return (memo[v] = i);
    }
  }
}

int main () {
  cin >> N;
  for (auto i = 0; i < N; ++i) {
    cin >> p[i];
    p[i]--;
  }
  for (auto i = 0; i < N; ++i) {
    V[p[i]].push_back(i);
  }
  fill(visited, visited+200010, false);
  int now = 0;
  while (!visited[now]) {
    visited[now] = true;
    now = p[now];
  }
  fill(isloop, isloop+200010, false);
  while (!isloop[now]) {
    // cerr << "loop: " << now << endl;
    isloop[now] = true;
    now = p[now];
  }
  // cerr << "now = " << now << endl;
  fill(memo, memo+200010, -1);
  for (auto i = 0; i < N; ++i) {
    if (!isloop[i]) {
      calc(i);
      // cerr << "calc(" << i << ") = " << calc(i) << endl;
    }
  }
  vector<int> kouho;
  set<int> S;
  for (auto x : V[now]) {
    if (!isloop[x]) {
      // cerr << "x = " << x << endl;
      S.insert(calc(x));
    }
  }
  for (auto i = 0; ; ++i) {
    if (S.find(i) == S.end()) {
      kouho.push_back(i);
      if (kouho.size() == 2) break;
    }
  }
  /*
  cerr << "kouho: ";
  for (auto x : kouho) {
    cerr << x << " ";
  }
  cerr << endl;
  */
  for (auto z : kouho) {
    for (auto i = 0; i < N; ++i) {
      if (isloop[i]) memo[i] = -1;
    }
    memo[now] = z;
    for (auto x : V[now]) {
      if (isloop[x]) calc(x);
    }
    /*
    for (auto i = 0; i < N; ++i) {
      if (isloop[i]) {
        cerr << "calc(" << i << ") = " << calc(i) << endl;
      }
    }
    */
    memo[now] = -1;
    // cerr << calc(now) << " " << z << endl;
    if (calc(now) == z) {
      cout << "POSSIBLE" << endl;
      return 0;
    }
  }
  cout << "IMPOSSIBLE" << endl;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
const ll infty = 1000000007;

struct edge {
  int to;
  ll cap;
  int rev;
};

bool visited[10010];
vector<edge> V[10010];

void add_edge(int from, int to, ll cap) {
  V[from].push_back(edge{to, cap, (int)V[to].size()});
  V[to].push_back(edge{from, 0, (int)V[from].size()-1});
}

ll dfs(int src, int dst, ll f) {
  if (src == dst) return f;
  visited[src] = true;
  for (auto &x : V[src]) {
    if (!visited[x.to] && x.cap > 0) {
      ll d = dfs(x.to, dst, min(f, x.cap));
      if (d > 0) {
        x.cap -= d;
        V[x.to][x.rev].cap += d;
        return d;
      }
    }
  }
  return 0;
}

ll max_flow(int src, int dst) {
  ll flow = 0;
  while (true) {
    fill(visited, visited+10010, false);
    ll f = dfs(src, dst, infty);
    if (f == 0) return flow;
    flow += f;
  }
}

int H, W;
string a[110];

int num(int i, int j) {
  return i * H + j;
}

int main () {
  cin >> H >> W;
  for (auto i = 0; i < H; ++i) {
    cin >> a[i];
  }
  int S, T;
  int si, sj, ti, tj;
  for (auto i = 0; i < H; ++i) {
    for (auto j = 0; j < W; ++j) {
      if (a[i][j] == 'S') {
        si = i;
        sj = j;
        S = num(i, j);
        a[i][j] = 'o';
      } else if (a[i][j] == 'T') {
        ti = i;
        tj = j;
        T = num(i, j);
        a[i][j] = 'o';
      }
    }
  }
  if (si == ti || sj == tj) {
    cout << -1 << endl;
    return 0;
  }
  for (auto i = 0; i < H; ++i) {
    vector<int> X;
    for (auto j = 0; j < W; ++j) {
      if (a[i][j] == 'o') {
        X.push_back(num(i, j));
      }
    }
    for (auto it = X.begin(); it+1 != X.end(); ++it) {
      add_edge(*it, *(it+1), 1);
      add_edge(*(it+1), *it, 1);
    }
  }
  for (auto j = 0; j < W; ++j) {
    vector<int> X;
    for (auto i = 0; i < H; ++i) {
      if (a[i][j] == 'o') {
        X.push_back(num(i, j));
      }
    }
    for (auto it = X.begin(); it != X.end(); ++it) {
      if (it+1 != X.end()) break;
      // cerr << *it << " " << *(it+1) << endl;
      add_edge(*it, *(it+1), 1);
      add_edge(*(it+1), *it, 1);
    }
  }
  // cout << max_flow(S, T) << endl;
}
<commit_msg>tried F.cpp to 'F'<commit_after>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
const ll infty = 1000000007;

struct edge {
  int to;
  ll cap;
  int rev;
};

bool visited[10010];
vector<edge> V[10010];

void add_edge(int from, int to, ll cap) {
  V[from].push_back(edge{to, cap, (int)V[to].size()});
  V[to].push_back(edge{from, 0, (int)V[from].size()-1});
}

ll dfs(int src, int dst, ll f) {
  if (src == dst) return f;
  visited[src] = true;
  for (auto &x : V[src]) {
    if (!visited[x.to] && x.cap > 0) {
      ll d = dfs(x.to, dst, min(f, x.cap));
      if (d > 0) {
        x.cap -= d;
        V[x.to][x.rev].cap += d;
        return d;
      }
    }
  }
  return 0;
}

ll max_flow(int src, int dst) {
  ll flow = 0;
  while (true) {
    fill(visited, visited+10010, false);
    ll f = dfs(src, dst, infty);
    if (f == 0) return flow;
    flow += f;
  }
}

int H, W;
string a[110];

int num(int i, int j) {
  return i * H + j;
}

int main () {
  cin >> H >> W;
  for (auto i = 0; i < H; ++i) {
    cin >> a[i];
  }
  int S, T;
  int si, sj, ti, tj;
  for (auto i = 0; i < H; ++i) {
    for (auto j = 0; j < W; ++j) {
      if (a[i][j] == 'S') {
        si = i;
        sj = j;
        S = num(i, j);
        a[i][j] = 'o';
      } else if (a[i][j] == 'T') {
        ti = i;
        tj = j;
        T = num(i, j);
        a[i][j] = 'o';
      }
    }
  }
  if (si == ti || sj == tj) {
    cout << -1 << endl;
    return 0;
  }
  for (auto i = 0; i < H; ++i) {
    vector<int> X;
    for (auto j = 0; j < W; ++j) {
      if (a[i][j] == 'o') {
        X.push_back(num(i, j));
      }
    }
    if (X.size() >= 2) {
      for (auto it = X.begin(); it+1 != X.end(); ++it) {
        add_edge(*it, *(it+1), 1);
        add_edge(*(it+1), *it, 1);
      }
    }
  }
  for (auto j = 0; j < W; ++j) {
    vector<int> X;
    for (auto i = 0; i < H; ++i) {
      if (a[i][j] == 'o') {
        X.push_back(num(i, j));
      }
    }
    if (X.size() >= 2) {
      for (auto it = X.begin(); it+1 != X.end(); ++it) {
        add_edge(*it, *(it+1), 1);
        add_edge(*(it+1), *it, 1);
      }
    }
  }
  // cout << max_flow(S, T) << endl;
}
<|endoftext|>