<commit_before>/*
 * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved.
 */

//
// sandesh_send_queue_test.cc
//
// Sandesh send queue Test
//

#include <map>
#include <arpa/inet.h>
#include <boost/tokenizer.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/find_iterator.hpp>
#include <boost/range/iterator_range.hpp>

#include "testing/gunit.h"

#include "base/logging.h"
#include "base/util.h"

#include <sandesh/protocol/TXMLProtocol.h>
#include <sandesh/protocol/TBinaryProtocol.h>
#include <sandesh/transport/TBufferTransports.h>

#include <sandesh/sandesh.h>
#include <sandesh/sandesh_types.h>
#include "sandesh_send_queue_test_types.h"

using namespace contrail::sandesh::protocol;
using namespace contrail::sandesh::transport;

static const int32_t test_i32 = 0xdeadbeef;
static const uint32_t test_list_size = 5;

static const int kQueueSize = 200 * 1024 * 1024;

class SandeshSendQueueTest : public ::testing::Test  {
protected:
    virtual void SetUp() {
        sandesh_queue_.reset(new Sandesh::SandeshQueue(TaskScheduler::
            GetInstance()->GetTaskId("sandesh::Test::SendQueueTest"
            "::sandesh_queue"),
            Task::kTaskInstanceAny,
                boost::bind(&SandeshSendQueueTest::DequeueEvent, this, _1),
                kQueueSize));
    }

    //Create a structure of size 278 bytes
    void CreateMessages() {
        uint8_t *buffer;
        uint32_t offset, wxfer, rxfer;
        // Initialize the struct
        msg1.set_i32Test(test_i32); //4 bytes
        // Create a vector of SandeshStructTest
        std::vector<SandeshListTestElement> test_list;
        for (uint32_t i = 0; i < test_list_size; i++) {
            SandeshListTestElement tmp;
            tmp.set_i32Elem(i);
            test_list.push_back(tmp); // 0, 1, 2, 3, 4
        }
        msg1.set_listTest(test_list);//20 bytes
        // Create a vector of int32_t
        std::vector<int32_t> test_basic_type_list;
        for (uint32_t i = 0; i < test_list_size; i++) {
            test_basic_type_list.push_back(i); // 0, 1, 2, 3, 4
        }
        msg1.set_basicTypeListTest(test_basic_type_list); //20 bytes
        // Create a vector of uuid
        std::vector<boost::uuids::uuid> test_uuid_list;
        for (uint32_t i = 0; i < test_list_size; i++) {
            boost::uuids::uuid uuid_temp =
                {0x00+i,0x00+i,0x01+i,0x01+i,0x02+i,0x02+i,0x03+i,0x03+i,
                 0x04+i,0x04+i,0x05+i,0x05+i,0x06+i,0x06+i,0x07+i,0x07+i};
            test_uuid_list.push_back(uuid_temp);
        }
        msg1.set_uuidListTest(test_uuid_list); //80 bytes
        // Create a map of <int32_t, string>
        std::map<int32_t, std::string> test_basic_type_map;
        for (uint32_t i = 0; i < test_list_size; i++) {
            // (0, "0"), (1, "1"), (2, "2"), (3, "3"), (4, "4")
            test_basic_type_map.insert(std::pair<int32_t, std::string>
                                       (i, integerToString(i)));
        }
        msg1.set_basicTypeMapTest(test_basic_type_map);//25 bytes
        // Create a map of <int32_t, SandeshListTestElement>
        std::map<int32_t, SandeshListTestElement> test_complex_type_map;
        for (uint32_t i = 0; i < test_list_size; i++) {
            SandeshListTestElement tmp;
            tmp.set_i32Elem(i);
            test_complex_type_map.insert(std::pair<int32_t, SandeshListTestElement>
                                         (i, tmp));
        }
        msg1.set_complexTypeMapTest(test_complex_type_map);//40 bytes
        msg1.set_u16Test(65535);//2 bytes
        msg1.set_u32Test(4294967295u);//4 bytes
        msg1.set_u64Test(18446744073709551615ull);//8 bytes
        msg1.set_ipv4Test(4294967295u);//4 bytes
        boost::uuids::uuid uuid_test =
             {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
              0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};//16 bytes
        msg1.set_uuidTest(uuid_test);
        msg1.set_xmlTest("<abc>");//5 bytes
        msg1.set_xmlTest1("abc");//3 bytes
        msg1.set_xmlTest2("ab]");//3 bytes
        msg1.set_xmlTest3("abc]]");//5 bytes
    }

    virtual void TearDown() {
    }

    bool DequeueEvent(SandeshElement element) {
        element.snh_->Release();
        return true;
    }

    boost::scoped_ptr<Sandesh::SandeshQueue> sandesh_queue_;
    SandeshStructTest msg1;
    SandeshStructTest msg2;
};

/*
 * Check if GetSize function works for the given sandesh
 */
TEST_F(SandeshSendQueueTest, SizeTest) {
    CreateMessages();
    SandeshResponseTest *sandesh = new SandeshResponseTest();
    sandesh->set_data(msg1);
    EXPECT_EQ(sandesh->GetSize(), 278);
    sandesh->Release();
}

/*
 * Check if sandesh queue size increases upon sending the message
 */
TEST_F(SandeshSendQueueTest, EnqueuTest) {
    CreateMessages();
    SandeshResponseTest *sandesh = new SandeshResponseTest();
    sandesh->set_data(msg1);
    //Intial size of queue is 0
    EXPECT_EQ(sandesh_queue_->Length(), 0);
    SandeshElement element_snd(sandesh), element_rcv;
    sandesh_queue_->Enqueue(element_snd);
    //Size of queue after enqueue
    EXPECT_EQ(sandesh_queue_->Length(), element_snd.GetSize());
    sandesh_queue_->Dequeue(&element_rcv);
    //Size of queue after dequeue
    EXPECT_EQ(sandesh_queue_->Length(), 0);
    sandesh->Release();
}

int main(int argc, char **argv) {
    LoggingInit();
    ::testing::InitGoogleTest(&argc, argv);
    bool success = RUN_ALL_TESTS();
    return success;
}
<commit_msg>Fix compilation failure in sandesh_send_queue_test<commit_after>/*
 * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved.
 */

//
// sandesh_send_queue_test.cc
//
// Sandesh send queue Test
//

#include <map>
#include <arpa/inet.h>
#include <boost/tokenizer.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/find_iterator.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/bind.hpp>

#include "testing/gunit.h"

#include "base/logging.h"
#include "base/util.h"

#include <sandesh/protocol/TXMLProtocol.h>
#include <sandesh/protocol/TBinaryProtocol.h>
#include <sandesh/transport/TBufferTransports.h>

#include <sandesh/sandesh.h>
#include <sandesh/sandesh_types.h>
#include "sandesh_send_queue_test_types.h"

using namespace contrail::sandesh::protocol;
using namespace contrail::sandesh::transport;

static const int32_t test_i32 = 0xdeadbeef;
static const uint32_t test_list_size = 5;

static const int kQueueSize = 200 * 1024 * 1024;

class SandeshSendQueueTest : public ::testing::Test  {
protected:
    virtual void SetUp() {
        sandesh_queue_.reset(new Sandesh::SandeshQueue(TaskScheduler::
            GetInstance()->GetTaskId("sandesh::Test::SendQueueTest"
            "::sandesh_queue"),
            Task::kTaskInstanceAny,
                boost::bind(&SandeshSendQueueTest::DequeueEvent, this, _1),
                kQueueSize));
    }

    //Create a structure of size 278 bytes
    void CreateMessages() {
        uint8_t *buffer;
        uint32_t offset, wxfer, rxfer;
        // Initialize the struct
        msg1.set_i32Test(test_i32); //4 bytes
        // Create a vector of SandeshStructTest
        std::vector<SandeshListTestElement> test_list;
        for (uint32_t i = 0; i < test_list_size; i++) {
            SandeshListTestElement tmp;
            tmp.set_i32Elem(i);
            test_list.push_back(tmp); // 0, 1, 2, 3, 4
        }
        msg1.set_listTest(test_list);//20 bytes
        // Create a vector of int32_t
        std::vector<int32_t> test_basic_type_list;
        for (uint32_t i = 0; i < test_list_size; i++) {
            test_basic_type_list.push_back(i); // 0, 1, 2, 3, 4
        }
        msg1.set_basicTypeListTest(test_basic_type_list); //20 bytes
        // Create a vector of uuid
        std::vector<boost::uuids::uuid> test_uuid_list;
        for (uint32_t i = 0; i < test_list_size; i++) {
            boost::uuids::uuid uuid_temp =
                {0x00+i,0x00+i,0x01+i,0x01+i,0x02+i,0x02+i,0x03+i,0x03+i,
                 0x04+i,0x04+i,0x05+i,0x05+i,0x06+i,0x06+i,0x07+i,0x07+i};
            test_uuid_list.push_back(uuid_temp);
        }
        msg1.set_uuidListTest(test_uuid_list); //80 bytes
        // Create a map of <int32_t, string>
        std::map<int32_t, std::string> test_basic_type_map;
        for (uint32_t i = 0; i < test_list_size; i++) {
            // (0, "0"), (1, "1"), (2, "2"), (3, "3"), (4, "4")
            test_basic_type_map.insert(std::pair<int32_t, std::string>
                                       (i, integerToString(i)));
        }
        msg1.set_basicTypeMapTest(test_basic_type_map);//25 bytes
        // Create a map of <int32_t, SandeshListTestElement>
        std::map<int32_t, SandeshListTestElement> test_complex_type_map;
        for (uint32_t i = 0; i < test_list_size; i++) {
            SandeshListTestElement tmp;
            tmp.set_i32Elem(i);
            test_complex_type_map.insert(std::pair<int32_t, SandeshListTestElement>
                                         (i, tmp));
        }
        msg1.set_complexTypeMapTest(test_complex_type_map);//40 bytes
        msg1.set_u16Test(65535);//2 bytes
        msg1.set_u32Test(4294967295u);//4 bytes
        msg1.set_u64Test(18446744073709551615ull);//8 bytes
        msg1.set_ipv4Test(4294967295u);//4 bytes
        boost::uuids::uuid uuid_test =
             {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
              0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};//16 bytes
        msg1.set_uuidTest(uuid_test);
        msg1.set_xmlTest("<abc>");//5 bytes
        msg1.set_xmlTest1("abc");//3 bytes
        msg1.set_xmlTest2("ab]");//3 bytes
        msg1.set_xmlTest3("abc]]");//5 bytes
    }

    virtual void TearDown() {
    }

    bool DequeueEvent(SandeshElement element) {
        element.snh_->Release();
        return true;
    }

    boost::scoped_ptr<Sandesh::SandeshQueue> sandesh_queue_;
    SandeshStructTest msg1;
    SandeshStructTest msg2;
};

/*
 * Check if GetSize function works for the given sandesh
 */
TEST_F(SandeshSendQueueTest, SizeTest) {
    CreateMessages();
    SandeshResponseTest *sandesh = new SandeshResponseTest();
    sandesh->set_data(msg1);
    EXPECT_EQ(sandesh->GetSize(), 278);
    sandesh->Release();
}

/*
 * Check if sandesh queue size increases upon sending the message
 */
TEST_F(SandeshSendQueueTest, EnqueuTest) {
    CreateMessages();
    SandeshResponseTest *sandesh = new SandeshResponseTest();
    sandesh->set_data(msg1);
    //Intial size of queue is 0
    EXPECT_EQ(sandesh_queue_->Length(), 0);
    SandeshElement element_snd(sandesh), element_rcv;
    sandesh_queue_->Enqueue(element_snd);
    //Size of queue after enqueue
    EXPECT_EQ(sandesh_queue_->Length(), element_snd.GetSize());
    sandesh_queue_->Dequeue(&element_rcv);
    //Size of queue after dequeue
    EXPECT_EQ(sandesh_queue_->Length(), 0);
    sandesh->Release();
}

int main(int argc, char **argv) {
    LoggingInit();
    ::testing::InitGoogleTest(&argc, argv);
    bool success = RUN_ALL_TESTS();
    return success;
}
<|endoftext|>


<commit_before>//
// Copyright 2011-2015 Jeff Bush
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

//
// The basic approach is based on this article:
// http://www.drdobbs.com/parallel/rasterization-on-larrabee/217200602
// And is also described in "Hierarchical polygon tiling with coverage
// masks" Proceedings of ACM SIGGRAPH 93, Ned Greene.
//

#include "Rasterizer.h"
#include "SIMDMath.h"

using namespace librender;

namespace
{

const int kMaxSweep = 0;
const veci16_t kXStep = { 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3 };
const veci16_t kYStep = { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3 };

void setupRecurseEdge(int tileLeft, int tileTop, int x1, int y1,
                      int x2, int y2, int &outAcceptEdgeValue, int &outRejectEdgeValue,
                      veci16_t &outAcceptStepMatrix, veci16_t &outRejectStepMatrix)
{
    veci16_t xAcceptStepValues = kXStep * (kTileSize / 4);
    veci16_t yAcceptStepValues = kYStep * (kTileSize / 4);
    veci16_t xRejectStepValues = xAcceptStepValues;
    veci16_t yRejectStepValues = yAcceptStepValues;
    int trivialAcceptX = tileLeft;
    int trivialAcceptY = tileTop;
    int trivialRejectX = tileLeft;
    int trivialRejectY = tileTop;
    const int kThreeQuarterTile = kTileSize * 3 / 4;

    if (y2 > y1)
    {
        trivialAcceptX += kTileSize - 1;
        xAcceptStepValues = xAcceptStepValues - kThreeQuarterTile;
    }
    else
    {
        trivialRejectX += kTileSize - 1;
        xRejectStepValues = xRejectStepValues - kThreeQuarterTile;
    }

    if (x2 > x1)
    {
        trivialRejectY += kTileSize - 1;
        yRejectStepValues = yRejectStepValues - kThreeQuarterTile;
    }
    else
    {
        trivialAcceptY += kTileSize - 1;
        yAcceptStepValues = yAcceptStepValues - kThreeQuarterTile;
    }

    int xStep = y2 - y1;
    int yStep = x2 - x1;

    outAcceptEdgeValue = (trivialAcceptX - x1) * xStep - (trivialAcceptY - y1) * yStep;
    outRejectEdgeValue = (trivialRejectX - x1) * xStep - (trivialRejectY - y1) * yStep;

    if (y1 > y2 || (y1 == y2 && x2 > x1))
    {
        // This is a top or left edge.  We adjust the edge equation values by one
        // so it doesn't overlap (top left fill convention).
        outAcceptEdgeValue++;
        outRejectEdgeValue++;
    }

    // Set up xStepValues
    xAcceptStepValues *= xStep;
    xRejectStepValues *= xStep;

    // Set up yStepValues
    yAcceptStepValues *= yStep;
    yRejectStepValues *= yStep;

    // Add together
    outAcceptStepMatrix = xAcceptStepValues - yAcceptStepValues;
    outRejectStepMatrix = xRejectStepValues - yRejectStepValues;
}

// Workhorse of recursive rasterization.  Subdivides tile into 4x4 grids.
void subdivideTile(
    TriangleFiller &filler,
    const int acceptCornerValue1,
    const int acceptCornerValue2,
    const int acceptCornerValue3,
    const int rejectCornerValue1,
    const int rejectCornerValue2,
    const int rejectCornerValue3,
    const veci16_t acceptStep1,
    const veci16_t acceptStep2,
    const veci16_t acceptStep3,
    const veci16_t rejectStep1,
    const veci16_t rejectStep2,
    const veci16_t rejectStep3,
    const int tileSizeBits,	// log2 tile size (1 << tileSizeBits = pixels)
    const int tileLeft,
    const int tileTop,
    const int clipRight,
    const int clipBottom)
{
    // Compute accept masks
    const veci16_t acceptEdgeValue1 = acceptStep1 + acceptCornerValue1;
    const veci16_t acceptEdgeValue2 = acceptStep2 + acceptCornerValue2;
    const veci16_t acceptEdgeValue3 = acceptStep3 + acceptCornerValue3;
    const unsigned int trivialAcceptMask = static_cast<unsigned int>(
        __builtin_nyuzi_mask_cmpi_sle(acceptEdgeValue1, veci16_t(0))
        & __builtin_nyuzi_mask_cmpi_sle(acceptEdgeValue2, veci16_t(0))
        & __builtin_nyuzi_mask_cmpi_sle(acceptEdgeValue3, veci16_t(0)));

    if (tileSizeBits == 2)
    {
        // End recursion
        if (trivialAcceptMask)
            filler.fillMasked(tileLeft, tileTop, trivialAcceptMask);

        return;
    }

    const int subTileSizeBits = tileSizeBits - 2;

    // Process all trivially accepted blocks
    if (trivialAcceptMask != 0)
    {
        unsigned int currentMask = trivialAcceptMask;

        while (currentMask)
        {
            const int index = __builtin_clz(currentMask) - 16;
            currentMask &= ~(0x8000 >> index);
            const int subTileLeft = tileLeft + ((index & 3) << subTileSizeBits);
            const int subTileTop = tileTop + ((index >> 2) << subTileSizeBits);
            const int tileCount = 1 << subTileSizeBits;
            const int hcount = min(tileCount, clipRight - subTileLeft);
            const int vcount = min(tileCount, clipBottom - subTileTop);
            for (int y = 0; y < vcount; y += 4)
            {
                for (int x = 0; x < hcount; x += 4)
                    filler.fillMasked(subTileLeft + x, subTileTop + y, 0xffff);
            }
        }
    }

    // Compute reject masks
    const veci16_t rejectEdgeValue1 = rejectStep1 + rejectCornerValue1;
    const veci16_t rejectEdgeValue2 = rejectStep2 + rejectCornerValue2;
    const veci16_t rejectEdgeValue3 = rejectStep3 + rejectCornerValue3;
    const unsigned int trivialRejectMask = static_cast<unsigned int>(
        __builtin_nyuzi_mask_cmpi_sgt(rejectEdgeValue1, veci16_t(0))
        | __builtin_nyuzi_mask_cmpi_sgt(rejectEdgeValue2, veci16_t(0))
        | __builtin_nyuzi_mask_cmpi_sgt(rejectEdgeValue3, veci16_t(0)));

    // Recurse into blocks that are neither trivially rejected or accepted.
    // They are partially overlapped and need to be further subdivided.
    unsigned int recurseMask = (trivialAcceptMask | trivialRejectMask) ^ 0xffff;
    if (recurseMask)
    {
        // Divide each step matrix by 4
        const veci16_t subAcceptStep1 = acceptStep1 >> 2;
        const veci16_t subAcceptStep2 = acceptStep2 >> 2;
        const veci16_t subAcceptStep3 = acceptStep3 >> 2;
        const veci16_t subRejectStep1 = rejectStep1 >> 2;
        const veci16_t subRejectStep2 = rejectStep2 >> 2;
        const veci16_t subRejectStep3 = rejectStep3 >> 2;

        while (recurseMask)
        {
            const int index = __builtin_clz(recurseMask) - 16;
            recurseMask &= ~(0x8000 >> index);
            const int x = tileLeft + ((index & 3) << subTileSizeBits);
            const int y = tileTop + ((index >> 2) << subTileSizeBits);
            if (x >= clipRight || y >= clipBottom)
                continue;	// Clip tiles that are outside viewport

            subdivideTile(
                filler,
                acceptEdgeValue1[index],
                acceptEdgeValue2[index],
                acceptEdgeValue3[index],
                rejectEdgeValue1[index],
                rejectEdgeValue2[index],
                rejectEdgeValue3[index],
                subAcceptStep1,
                subAcceptStep2,
                subAcceptStep3,
                subRejectStep1,
                subRejectStep2,
                subRejectStep3,
                subTileSizeBits,
                x,
                y,
                clipRight,
                clipBottom);
        }
    }
}

void rasterizeRecursive(TriangleFiller &filler,
                        int tileLeft, int tileTop, int clipRight, int clipBottom,
                        int x1, int y1, int x2, int y2, int x3, int y3)
{
    int acceptValue1;
    int rejectValue1;
    veci16_t acceptStepMatrix1;
    veci16_t rejectStepMatrix1;
    int acceptValue2;
    int rejectValue2;
    veci16_t acceptStepMatrix2;
    veci16_t rejectStepMatrix2;
    int acceptValue3;
    int rejectValue3;
    veci16_t acceptStepMatrix3;
    veci16_t rejectStepMatrix3;

    // This assumes counter-clockwise winding for triangles that are
    // facing the camera.
    setupRecurseEdge(tileLeft, tileTop, x1, y1, x3, y3, acceptValue1, rejectValue1,
                     acceptStepMatrix1, rejectStepMatrix1);
    setupRecurseEdge(tileLeft, tileTop, x3, y3, x2, y2, acceptValue2, rejectValue2,
                     acceptStepMatrix2, rejectStepMatrix2);
    setupRecurseEdge(tileLeft, tileTop, x2, y2, x1, y1, acceptValue3, rejectValue3,
                     acceptStepMatrix3, rejectStepMatrix3);

    subdivideTile(
        filler,
        acceptValue1,
        acceptValue2,
        acceptValue3,
        rejectValue1,
        rejectValue2,
        rejectValue3,
        acceptStepMatrix1,
        acceptStepMatrix2,
        acceptStepMatrix3,
        rejectStepMatrix1,
        rejectStepMatrix2,
        rejectStepMatrix3,
        __builtin_ctz(kTileSize),
        tileLeft,
        tileTop,
        clipRight,
        clipBottom);
}

inline int min3(int a, int b, int c)
{
    int value = a < b ? a : b;
    return c < value ? c : value;
}

inline int max3(int a, int b, int c)
{
    int value = a > b ? a : b;
    return c > value ? c : value;
}

inline void setupSweepEdge(int left, int top, int x1, int y1, int x2, int y2,
                           int &outXStep4, int &outYStep4, veci16_t &outEdgeValue)
{
    int xStep1 = y2 - y1;
    int yStep1 = x2 - x1;
    outEdgeValue = (kXStep + left - x2) * xStep1
                   - (kYStep + top - y2) * yStep1;
    if (y1 > y2 || (y1 == y2 && x2 > x1))
        outEdgeValue -= 1;	// Left or top edge

    outXStep4 = xStep1 * 4;
    outYStep4 = yStep1 * 4;
}

//
// For smaller triangles, this skips the setup overhead of the recursive rasterizer.
// It instead steps the 4x4 grid over the bounding box of the triangle in a serpentine
// pattern.
// Currently disabled.
//
void rasterizeSweep(TriangleFiller &filler,
                    int bbLeft, int bbTop, int bbRight, int bbBottom,
                    int x1, int y1, int x2, int y2, int x3, int y3)
{
    int xStep4_1;
    int yStep4_1;
    int xStep4_2;
    int yStep4_2;
    int xStep4_3;
    int yStep4_3;
    veci16_t edgeValue1;
    veci16_t edgeValue2;
    veci16_t edgeValue3;

    setupSweepEdge(bbLeft, bbTop, x1, y1, x2, y2, xStep4_1, yStep4_1, edgeValue1);
    setupSweepEdge(bbLeft, bbTop, x2, y2, x3, y3, xStep4_2, yStep4_2, edgeValue2);
    setupSweepEdge(bbLeft, bbTop, x3, y3, x1, y1, xStep4_3, yStep4_3, edgeValue3);

    int col = bbLeft;
    int row = bbTop;
    int stepDir = 4;
    do
    {
        for (int colCount = 0; ; colCount++)
        {
            int mask = __builtin_nyuzi_mask_cmpi_sge(edgeValue1, veci16_t(0))
                       & __builtin_nyuzi_mask_cmpi_sge(edgeValue2, veci16_t(0))
                       & __builtin_nyuzi_mask_cmpi_sge(edgeValue3, veci16_t(0));
            if (mask)
                filler.fillMasked(col, row, mask);

            if (colCount == kTileSize / 4)
                break;

            // Step left/right
            edgeValue1 += xStep4_1;
            edgeValue2 += xStep4_2;
            edgeValue3 += xStep4_3;
            col += stepDir;
        }

        // Change direction, step down
        xStep4_1 = -xStep4_1;
        xStep4_2 = -xStep4_2;
        xStep4_3 = -xStep4_3;
        stepDir = -stepDir;
        edgeValue1 -= yStep4_1;
        edgeValue2 -= yStep4_2;
        edgeValue3 -= yStep4_3;
        row += 4;
    }
    while (row < bbBottom);
}

}

void librender::fillTriangle(TriangleFiller &filler,
                             int tileLeft, int tileTop,
                             int x1, int y1, int x2, int y2, int x3, int y3,
                             int clipRight, int clipBottom)
{
    int bbLeft = max(min3(x1, x2, x3) & ~3, tileLeft);
    int bbTop = max(min3(y1, y2, y3) & ~3, tileTop);
    int bbRight = min3((max3(x1, x2, x3) + 3) & ~3, clipRight, tileLeft + kTileSize);
    int bbBottom = min3((max3(y1, y2, y3) + 3) & ~3, clipBottom, tileTop + kTileSize);

    if (bbRight - bbLeft < kMaxSweep && bbBottom - bbTop < kMaxSweep)
        rasterizeSweep(filler, bbLeft, bbTop, bbRight, bbBottom, x1, y1, x2, y2, x3, y3);
    else
    {
        rasterizeRecursive(filler, tileLeft, tileTop, clipRight, clipBottom,
                           x1, y1, x2, y2, x3, y3);
    }
}
<commit_msg>Use right side of bounding box when sweep rasterizing<commit_after>//
// Copyright 2011-2015 Jeff Bush
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

//
// The basic approach is based on this article:
// http://www.drdobbs.com/parallel/rasterization-on-larrabee/217200602
// And is also described in "Hierarchical polygon tiling with coverage
// masks" Proceedings of ACM SIGGRAPH 93, Ned Greene.
//

#include "Rasterizer.h"
#include "SIMDMath.h"

using namespace librender;

namespace
{

const int kMaxSweep = 0;
const veci16_t kXStep = { 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3 };
const veci16_t kYStep = { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3 };

void setupRecurseEdge(int tileLeft, int tileTop, int x1, int y1,
                      int x2, int y2, int &outAcceptEdgeValue, int &outRejectEdgeValue,
                      veci16_t &outAcceptStepMatrix, veci16_t &outRejectStepMatrix)
{
    veci16_t xAcceptStepValues = kXStep * (kTileSize / 4);
    veci16_t yAcceptStepValues = kYStep * (kTileSize / 4);
    veci16_t xRejectStepValues = xAcceptStepValues;
    veci16_t yRejectStepValues = yAcceptStepValues;
    int trivialAcceptX = tileLeft;
    int trivialAcceptY = tileTop;
    int trivialRejectX = tileLeft;
    int trivialRejectY = tileTop;
    const int kThreeQuarterTile = kTileSize * 3 / 4;

    if (y2 > y1)
    {
        trivialAcceptX += kTileSize - 1;
        xAcceptStepValues = xAcceptStepValues - kThreeQuarterTile;
    }
    else
    {
        trivialRejectX += kTileSize - 1;
        xRejectStepValues = xRejectStepValues - kThreeQuarterTile;
    }

    if (x2 > x1)
    {
        trivialRejectY += kTileSize - 1;
        yRejectStepValues = yRejectStepValues - kThreeQuarterTile;
    }
    else
    {
        trivialAcceptY += kTileSize - 1;
        yAcceptStepValues = yAcceptStepValues - kThreeQuarterTile;
    }

    int xStep = y2 - y1;
    int yStep = x2 - x1;

    outAcceptEdgeValue = (trivialAcceptX - x1) * xStep - (trivialAcceptY - y1) * yStep;
    outRejectEdgeValue = (trivialRejectX - x1) * xStep - (trivialRejectY - y1) * yStep;

    if (y1 > y2 || (y1 == y2 && x2 > x1))
    {
        // This is a top or left edge.  We adjust the edge equation values by one
        // so it doesn't overlap (top left fill convention).
        outAcceptEdgeValue++;
        outRejectEdgeValue++;
    }

    // Set up xStepValues
    xAcceptStepValues *= xStep;
    xRejectStepValues *= xStep;

    // Set up yStepValues
    yAcceptStepValues *= yStep;
    yRejectStepValues *= yStep;

    // Add together
    outAcceptStepMatrix = xAcceptStepValues - yAcceptStepValues;
    outRejectStepMatrix = xRejectStepValues - yRejectStepValues;
}

// Workhorse of recursive rasterization.  Subdivides tile into 4x4 grids.
void subdivideTile(
    TriangleFiller &filler,
    const int acceptCornerValue1,
    const int acceptCornerValue2,
    const int acceptCornerValue3,
    const int rejectCornerValue1,
    const int rejectCornerValue2,
    const int rejectCornerValue3,
    const veci16_t acceptStep1,
    const veci16_t acceptStep2,
    const veci16_t acceptStep3,
    const veci16_t rejectStep1,
    const veci16_t rejectStep2,
    const veci16_t rejectStep3,
    const int tileSizeBits,	// log2 tile size (1 << tileSizeBits = pixels)
    const int tileLeft,
    const int tileTop,
    const int clipRight,
    const int clipBottom)
{
    // Compute accept masks
    const veci16_t acceptEdgeValue1 = acceptStep1 + acceptCornerValue1;
    const veci16_t acceptEdgeValue2 = acceptStep2 + acceptCornerValue2;
    const veci16_t acceptEdgeValue3 = acceptStep3 + acceptCornerValue3;
    const unsigned int trivialAcceptMask = static_cast<unsigned int>(
        __builtin_nyuzi_mask_cmpi_sle(acceptEdgeValue1, veci16_t(0))
        & __builtin_nyuzi_mask_cmpi_sle(acceptEdgeValue2, veci16_t(0))
        & __builtin_nyuzi_mask_cmpi_sle(acceptEdgeValue3, veci16_t(0)));

    if (tileSizeBits == 2)
    {
        // End recursion
        if (trivialAcceptMask)
            filler.fillMasked(tileLeft, tileTop, trivialAcceptMask);

        return;
    }

    const int subTileSizeBits = tileSizeBits - 2;

    // Process all trivially accepted blocks
    if (trivialAcceptMask != 0)
    {
        unsigned int currentMask = trivialAcceptMask;

        while (currentMask)
        {
            const int index = __builtin_clz(currentMask) - 16;
            currentMask &= ~(0x8000 >> index);
            const int subTileLeft = tileLeft + ((index & 3) << subTileSizeBits);
            const int subTileTop = tileTop + ((index >> 2) << subTileSizeBits);
            const int tileCount = 1 << subTileSizeBits;
            const int hcount = min(tileCount, clipRight - subTileLeft);
            const int vcount = min(tileCount, clipBottom - subTileTop);
            for (int y = 0; y < vcount; y += 4)
            {
                for (int x = 0; x < hcount; x += 4)
                    filler.fillMasked(subTileLeft + x, subTileTop + y, 0xffff);
            }
        }
    }

    // Compute reject masks
    const veci16_t rejectEdgeValue1 = rejectStep1 + rejectCornerValue1;
    const veci16_t rejectEdgeValue2 = rejectStep2 + rejectCornerValue2;
    const veci16_t rejectEdgeValue3 = rejectStep3 + rejectCornerValue3;
    const unsigned int trivialRejectMask = static_cast<unsigned int>(
        __builtin_nyuzi_mask_cmpi_sgt(rejectEdgeValue1, veci16_t(0))
        | __builtin_nyuzi_mask_cmpi_sgt(rejectEdgeValue2, veci16_t(0))
        | __builtin_nyuzi_mask_cmpi_sgt(rejectEdgeValue3, veci16_t(0)));

    // Recurse into blocks that are neither trivially rejected or accepted.
    // They are partially overlapped and need to be further subdivided.
    unsigned int recurseMask = (trivialAcceptMask | trivialRejectMask) ^ 0xffff;
    if (recurseMask)
    {
        // Divide each step matrix by 4
        const veci16_t subAcceptStep1 = acceptStep1 >> 2;
        const veci16_t subAcceptStep2 = acceptStep2 >> 2;
        const veci16_t subAcceptStep3 = acceptStep3 >> 2;
        const veci16_t subRejectStep1 = rejectStep1 >> 2;
        const veci16_t subRejectStep2 = rejectStep2 >> 2;
        const veci16_t subRejectStep3 = rejectStep3 >> 2;

        while (recurseMask)
        {
            const int index = __builtin_clz(recurseMask) - 16;
            recurseMask &= ~(0x8000 >> index);
            const int x = tileLeft + ((index & 3) << subTileSizeBits);
            const int y = tileTop + ((index >> 2) << subTileSizeBits);
            if (x >= clipRight || y >= clipBottom)
                continue;	// Clip tiles that are outside viewport

            subdivideTile(
                filler,
                acceptEdgeValue1[index],
                acceptEdgeValue2[index],
                acceptEdgeValue3[index],
                rejectEdgeValue1[index],
                rejectEdgeValue2[index],
                rejectEdgeValue3[index],
                subAcceptStep1,
                subAcceptStep2,
                subAcceptStep3,
                subRejectStep1,
                subRejectStep2,
                subRejectStep3,
                subTileSizeBits,
                x,
                y,
                clipRight,
                clipBottom);
        }
    }
}

void rasterizeRecursive(TriangleFiller &filler,
                        int tileLeft, int tileTop, int clipRight, int clipBottom,
                        int x1, int y1, int x2, int y2, int x3, int y3)
{
    int acceptValue1;
    int rejectValue1;
    veci16_t acceptStepMatrix1;
    veci16_t rejectStepMatrix1;
    int acceptValue2;
    int rejectValue2;
    veci16_t acceptStepMatrix2;
    veci16_t rejectStepMatrix2;
    int acceptValue3;
    int rejectValue3;
    veci16_t acceptStepMatrix3;
    veci16_t rejectStepMatrix3;

    // This assumes counter-clockwise winding for triangles that are
    // facing the camera.
    setupRecurseEdge(tileLeft, tileTop, x1, y1, x3, y3, acceptValue1, rejectValue1,
                     acceptStepMatrix1, rejectStepMatrix1);
    setupRecurseEdge(tileLeft, tileTop, x3, y3, x2, y2, acceptValue2, rejectValue2,
                     acceptStepMatrix2, rejectStepMatrix2);
    setupRecurseEdge(tileLeft, tileTop, x2, y2, x1, y1, acceptValue3, rejectValue3,
                     acceptStepMatrix3, rejectStepMatrix3);

    subdivideTile(
        filler,
        acceptValue1,
        acceptValue2,
        acceptValue3,
        rejectValue1,
        rejectValue2,
        rejectValue3,
        acceptStepMatrix1,
        acceptStepMatrix2,
        acceptStepMatrix3,
        rejectStepMatrix1,
        rejectStepMatrix2,
        rejectStepMatrix3,
        __builtin_ctz(kTileSize),
        tileLeft,
        tileTop,
        clipRight,
        clipBottom);
}

inline int min3(int a, int b, int c)
{
    int value = a < b ? a : b;
    return c < value ? c : value;
}

inline int max3(int a, int b, int c)
{
    int value = a > b ? a : b;
    return c > value ? c : value;
}

inline void setupSweepEdge(int left, int top, int x1, int y1, int x2, int y2,
                           int &outXStep4, int &outYStep4, veci16_t &outEdgeValue)
{
    int xStep1 = y2 - y1;
    int yStep1 = x2 - x1;
    outEdgeValue = (kXStep + left - x2) * xStep1
                   - (kYStep + top - y2) * yStep1;
    if (y1 > y2 || (y1 == y2 && x2 > x1))
        outEdgeValue -= 1;	// Left or top edge

    outXStep4 = xStep1 * 4;
    outYStep4 = yStep1 * 4;
}

//
// For smaller triangles, this skips the setup overhead of the recursive rasterizer.
// It instead steps the 4x4 grid over the bounding box of the triangle in a serpentine
// pattern.
// Currently disabled.
//
void rasterizeSweep(TriangleFiller &filler,
                    int bbLeft, int bbTop, int bbRight, int bbBottom,
                    int x1, int y1, int x2, int y2, int x3, int y3)
{
    int xStep4_1;
    int yStep4_1;
    int xStep4_2;
    int yStep4_2;
    int xStep4_3;
    int yStep4_3;
    veci16_t edgeValue1;
    veci16_t edgeValue2;
    veci16_t edgeValue3;

    setupSweepEdge(bbLeft, bbTop, x1, y1, x2, y2, xStep4_1, yStep4_1, edgeValue1);
    setupSweepEdge(bbLeft, bbTop, x2, y2, x3, y3, xStep4_2, yStep4_2, edgeValue2);
    setupSweepEdge(bbLeft, bbTop, x3, y3, x1, y1, xStep4_3, yStep4_3, edgeValue3);

    int col = bbLeft;
    int row = bbTop;
    int stepDir = 4;
    int numCols = (bbRight - bbLeft) / 4;
    do
    {
        for (int colCount = 0; ; colCount++)
        {
            int mask = __builtin_nyuzi_mask_cmpi_sge(edgeValue1, veci16_t(0))
                       & __builtin_nyuzi_mask_cmpi_sge(edgeValue2, veci16_t(0))
                       & __builtin_nyuzi_mask_cmpi_sge(edgeValue3, veci16_t(0));
            if (mask)
                filler.fillMasked(col, row, mask);

            if (colCount == numCols)
                break;

            // Step left/right
            edgeValue1 += xStep4_1;
            edgeValue2 += xStep4_2;
            edgeValue3 += xStep4_3;
            col += stepDir;
        }

        // Change direction, step down
        xStep4_1 = -xStep4_1;
        xStep4_2 = -xStep4_2;
        xStep4_3 = -xStep4_3;
        stepDir = -stepDir;
        edgeValue1 -= yStep4_1;
        edgeValue2 -= yStep4_2;
        edgeValue3 -= yStep4_3;
        row += 4;
    }
    while (row < bbBottom);
}

}

void librender::fillTriangle(TriangleFiller &filler,
                             int tileLeft, int tileTop,
                             int x1, int y1, int x2, int y2, int x3, int y3,
                             int clipRight, int clipBottom)
{
    int bbLeft = max(min3(x1, x2, x3) & ~3, tileLeft);
    int bbTop = max(min3(y1, y2, y3) & ~3, tileTop);
    int bbRight = min3((max3(x1, x2, x3) + 3) & ~3, clipRight, tileLeft + kTileSize);
    int bbBottom = min3((max3(y1, y2, y3) + 3) & ~3, clipBottom, tileTop + kTileSize);

    if (bbRight - bbLeft < kMaxSweep && bbBottom - bbTop < kMaxSweep)
        rasterizeSweep(filler, bbLeft, bbTop, bbRight, bbBottom, x1, y1, x2, y2, x3, y3);
    else
    {
        rasterizeRecursive(filler, tileLeft, tileTop, clipRight, clipBottom,
                           x1, y1, x2, y2, x3, y3);
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 Henrik Steffen Gaßmann
//
// Licensed under the MIT License.
// See LICENSE file in the project root for full license information.
//
//#include "precompiled.hpp"
#include <sexpr-cpp/data.hpp>

#include "data-helpers.hpp"
#include "boost-unit-test.hpp"

BOOST_TEST_DONT_PRINT_LOG_VALUE(std::type_info)
using namespace sexpr;

BOOST_AUTO_TEST_SUITE(basic_node)

BOOST_AUTO_TEST_SUITE(ctor_tests)

BOOST_AUTO_TEST_CASE(default_ctor)
{
    node n;
    BOOST_TEST_REQUIRE(n.which() == node_type::list);
    BOOST_TEST(n.is_list());
    BOOST_TEST(n.type_info() == typeid(node::list));

    BOOST_TEST(n.empty());
}

BOOST_AUTO_TEST_CASE(char_array_ctor)
{
    static constexpr char raw_str[] = "foo\0bar";
    const std::string str_w_null(raw_str, sizeof(raw_str));
    const auto str = str_w_null.substr(0, str_w_null.size() - 1);

    node n1(raw_str);
    BOOST_TEST_REQUIRE(n1.is_string());
    BOOST_TEST(n1.get_string() == str);

    node n2(raw_str, false);
    BOOST_TEST_REQUIRE(n2.is_string());
    BOOST_TEST(n2.get_string() == str_w_null);
}

BOOST_AUTO_TEST_CASE(string_ctor)
{
    using namespace std::string_literals;
    auto refstr = "foobar\0baz"s;
    node n(refstr);

    BOOST_TEST_REQUIRE(n.is_string());
    BOOST_TEST(n.type_info() == typeid(node::string));
    auto &s = n.get_string();
    BOOST_TEST(s.size() == refstr.size());
    BOOST_TEST(s == refstr);
}

BOOST_AUTO_TEST_CASE(init_ctor__empty)
{
    node n{};
    BOOST_TEST_REQUIRE(n.is_list());
    BOOST_TEST(n.empty());
}

BOOST_AUTO_TEST_CASE(init_ctor__single)
{
    using namespace std::string_literals;
    const auto s1 = "foo"s;

    node n{ s1 };
    BOOST_TEST_REQUIRE(n.is_list());
    BOOST_TEST_REQUIRE(!n.empty());
    BOOST_TEST(n.size() == 1);
    BOOST_TEST(n.at(0).is_string());
    BOOST_TEST(n.at(0).get_string() == s1);
}

BOOST_AUTO_TEST_CASE(init_ctor__multi)
{
    using namespace std::string_literals;
    std::string s1 = "foo", s2 = "bar", s3 = "baz";

    node n{ s1,s2,s3 };
    BOOST_TEST_REQUIRE(n.is_list());
    BOOST_TEST_REQUIRE(!n.empty());
    BOOST_TEST(n.size() == 3);
    BOOST_TEST(n.at(0).is_string());
    BOOST_TEST(n.at(0).get_string() == s1);
    BOOST_TEST(n.at(1).is_string());
    BOOST_TEST(n.at(1).get_string() == s2);
    BOOST_TEST(n.at(2).is_string());
    BOOST_TEST(s3 == n.at(2).get_string());
}

BOOST_AUTO_TEST_CASE(init_ctor__complex)
{
    node n{ "foo",{ "bar", "baz" },{ "foobar" }, "oh my" };
    BOOST_TEST_REQUIRE(n.is_list());
    BOOST_TEST_REQUIRE(n.size() == 4);
    BOOST_TEST(n[0].is_string());
    BOOST_TEST(n[1].is_list());
    BOOST_TEST(n[1].size() == 2);
    BOOST_TEST(n[1][0].is_string());
    BOOST_TEST(n[2].is_list());
    BOOST_TEST(n[2].size() == 1);
    BOOST_TEST(n[3].is_string());
}

BOOST_AUTO_TEST_CASE(copy_ctor)
{
    using namespace std::string_literals;
    node n0{ "foo"s, { "bar"s, "baz"s }, {"foobar"s}, "oh my"s };
    node n1 = n0;

    BOOST_TEST(n0 == n1);
}

BOOST_AUTO_TEST_SUITE_END()

struct accessor_fixture
{
    static constexpr char str_raw[] = "foobar";
    const std::string str = str_raw;
    node str_node;
    const node &str_cnode;

    const std::vector<node> node_vector = { "first", "second", "third" };
    node list_node;
    const node &list_cnode;

    accessor_fixture()
        : str_node(str_raw)
        , str_cnode(str_node)
        , list_node()
        , list_cnode(list_node)
    {
        list_node = node(node_vector.begin(), node_vector.end());
    }
};

constexpr char accessor_fixture::str_raw[];

BOOST_FIXTURE_TEST_SUITE(accessor_tests, accessor_fixture)

using namespace std::string_literals;

BOOST_AUTO_TEST_CASE(string_getters)
{
    BOOST_TEST(str_node.is_string());
    BOOST_TEST(!str_node.get_string().compare(str));
    BOOST_CHECK_THROW(str_node.get_list(), std::domain_error);
    BOOST_TEST_REQUIRE(str_node.try_get_string());
    BOOST_TEST(!str_node.try_get_string()->compare(str));
    BOOST_TEST(!str_node.try_get_list());

    BOOST_TEST(str_cnode.is_string());
    BOOST_TEST(!str_cnode.get_string().compare(str));
    BOOST_CHECK_THROW(str_cnode.get_list(), std::domain_error);
    BOOST_TEST_REQUIRE(str_cnode.try_get_string());
    BOOST_TEST(!str_cnode.try_get_string()->compare(str));
    BOOST_TEST(!str_cnode.try_get_list());
}

BOOST_AUTO_TEST_CASE(list_getters)
{
    BOOST_TEST(list_node.is_list());
    BOOST_TEST(list_node.get_list() == node_vector);
    BOOST_CHECK_THROW(list_node.get_string(), std::domain_error);
    BOOST_TEST_REQUIRE(list_node.try_get_list());
    BOOST_TEST(*list_node.try_get_list() == node_vector);
    BOOST_TEST(!list_node.try_get_string());

    BOOST_TEST(list_cnode.is_list());
    BOOST_TEST(list_cnode.get_list() == node_vector);
    BOOST_CHECK_THROW(list_cnode.get_string(), std::domain_error);
    BOOST_TEST_REQUIRE(list_cnode.try_get_list());
    BOOST_TEST(*list_cnode.try_get_list() == node_vector);
    BOOST_TEST(!list_cnode.try_get_string());
}

BOOST_AUTO_TEST_CASE(list_container_emulation)
{
    BOOST_TEST(list_node.get_list() == node_vector);

    BOOST_TEST(list_node.at(0) == node_vector.at(0));
    BOOST_TEST(list_node.at(1) == node_vector.at(1));
    BOOST_TEST(list_node.at(2) == node_vector.at(2));
    BOOST_TEST(list_cnode.at(0) == node_vector.at(0));
    BOOST_TEST(list_cnode.at(1) == node_vector.at(1));
    BOOST_TEST(list_cnode.at(2) == node_vector.at(2));

    BOOST_CHECK_THROW(list_node.at(3), std::exception);
    BOOST_TEST(list_node.at(0) == list_node[0]);
    BOOST_TEST(list_node.at(1) == list_node[1]);
    BOOST_TEST(list_node.at(2) == list_node[2]);
    BOOST_TEST(list_node.at(0) == list_cnode[0]);
    BOOST_TEST(list_node.at(1) == list_cnode[1]);
    BOOST_TEST(list_node.at(2) == list_cnode[2]);

    BOOST_TEST(list_node.front() == node_vector.front());
    BOOST_TEST(list_cnode.front() == node_vector.front());

    BOOST_TEST(list_node.back() == node_vector.back());
    BOOST_TEST(list_cnode.back() == node_vector.back());

    BOOST_TEST(list_node.empty() == node_vector.empty());
    BOOST_TEST(list_cnode.empty() == node_vector.empty());

    BOOST_TEST(list_node.size() == node_vector.size());
    BOOST_TEST(list_cnode.size() == node_vector.size());

    BOOST_TEST(list_node.max_size() >= list_node.size());
    BOOST_TEST(list_cnode.max_size() >= list_cnode.size());
    BOOST_TEST(list_cnode.max_size() >= list_node.max_size());
}

BOOST_AUTO_TEST_CASE(string_container_emulation)
{
    BOOST_CHECK_THROW(str_node.at(0), std::domain_error);
    BOOST_CHECK_THROW(str_node.at(1), std::domain_error);
    BOOST_CHECK_THROW(str_cnode.at(0), std::domain_error);
    BOOST_CHECK_THROW(str_cnode.at(1), std::domain_error);

    BOOST_CHECK_THROW(str_node[0], std::domain_error);
    BOOST_CHECK_THROW(str_node[1], std::domain_error);
    BOOST_CHECK_THROW(str_cnode[0], std::domain_error);
    BOOST_CHECK_THROW(str_cnode[1], std::domain_error);

    BOOST_CHECK_THROW(str_node.front(), std::domain_error);
    BOOST_CHECK_THROW(str_cnode.front(), std::domain_error);

    BOOST_CHECK_THROW(str_node.back(), std::domain_error);
    BOOST_CHECK_THROW(str_cnode.back(), std::domain_error);

    BOOST_TEST(!str_node.empty());
    BOOST_TEST(!str_cnode.empty());

    BOOST_TEST(str_node.size() == 1);
    BOOST_TEST(str_cnode.size() == 1);

    BOOST_TEST(str_node.max_size() == 1);
    BOOST_TEST(str_cnode.max_size() == 1);
}

BOOST_AUTO_TEST_CASE(explicit_string_conversion)
{
    node::string s(str_cnode);
    BOOST_TEST(s == str_cnode.get_string());
    BOOST_TEST(static_cast<node::string>(str_cnode) == str_cnode.get_string());

    BOOST_CHECK_THROW(static_cast<node::string>(list_cnode), std::domain_error);
}

BOOST_AUTO_TEST_CASE(string_container_iterators)
{
    BOOST_CHECK_THROW(str_node.begin(), std::domain_error);
    BOOST_CHECK_THROW(str_cnode.begin(), std::domain_error);
    BOOST_CHECK_THROW(str_node.cbegin(), std::domain_error);

    BOOST_CHECK_THROW(str_node.end(), std::domain_error);
    BOOST_CHECK_THROW(str_cnode.end(), std::domain_error);
    BOOST_CHECK_THROW(str_node.cend(), std::domain_error);

    BOOST_CHECK_THROW(str_node.rbegin(), std::domain_error);
    BOOST_CHECK_THROW(str_cnode.rbegin(), std::domain_error);
    BOOST_CHECK_THROW(str_node.crbegin(), std::domain_error);

    BOOST_CHECK_THROW(str_node.rend(), std::domain_error);
    BOOST_CHECK_THROW(str_cnode.rend(), std::domain_error);
    BOOST_CHECK_THROW(str_node.crend(), std::domain_error);
}

BOOST_AUTO_TEST_CASE(list_container_iterators)
{
    BOOST_CHECK_EQUAL_COLLECTIONS(list_node.begin(), list_node.end(),
        node_vector.begin(), node_vector.end());
    BOOST_CHECK_EQUAL_COLLECTIONS(list_cnode.begin(), list_cnode.end(),
        node_vector.begin(), node_vector.end());
    BOOST_CHECK_EQUAL_COLLECTIONS(list_cnode.cbegin(), list_cnode.cend(),
        node_vector.begin(), node_vector.end());

    BOOST_CHECK_EQUAL_COLLECTIONS(list_node.rbegin(), list_node.rend(),
        node_vector.rbegin(), node_vector.rend());
    BOOST_CHECK_EQUAL_COLLECTIONS(list_cnode.rbegin(), list_cnode.rend(),
        node_vector.rbegin(), node_vector.rend());
    BOOST_CHECK_EQUAL_COLLECTIONS(list_cnode.crbegin(), list_cnode.crend(),
        node_vector.rbegin(), node_vector.rend());
}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>ADD basic_node STRING CONTAINER OPERATION TESTS<commit_after>// Copyright 2017 Henrik Steffen Gaßmann
//
// Licensed under the MIT License.
// See LICENSE file in the project root for full license information.
//
//#include "precompiled.hpp"
#include <sexpr-cpp/data.hpp>

#include "data-helpers.hpp"
#include "boost-unit-test.hpp"

BOOST_TEST_DONT_PRINT_LOG_VALUE(std::type_info)
using namespace sexpr;

BOOST_AUTO_TEST_SUITE(basic_node)

BOOST_AUTO_TEST_SUITE(ctor_tests)

BOOST_AUTO_TEST_CASE(default_ctor)
{
    node n;
    BOOST_TEST_REQUIRE(n.which() == node_type::list);
    BOOST_TEST(n.is_list());
    BOOST_TEST(n.type_info() == typeid(node::list));

    BOOST_TEST(n.empty());
}

BOOST_AUTO_TEST_CASE(char_array_ctor)
{
    static constexpr char raw_str[] = "foo\0bar";
    const std::string str_w_null(raw_str, sizeof(raw_str));
    const auto str = str_w_null.substr(0, str_w_null.size() - 1);

    node n1(raw_str);
    BOOST_TEST_REQUIRE(n1.is_string());
    BOOST_TEST(n1.get_string() == str);

    node n2(raw_str, false);
    BOOST_TEST_REQUIRE(n2.is_string());
    BOOST_TEST(n2.get_string() == str_w_null);
}

BOOST_AUTO_TEST_CASE(string_ctor)
{
    using namespace std::string_literals;
    auto refstr = "foobar\0baz"s;
    node n(refstr);

    BOOST_TEST_REQUIRE(n.is_string());
    BOOST_TEST(n.type_info() == typeid(node::string));
    auto &s = n.get_string();
    BOOST_TEST(s.size() == refstr.size());
    BOOST_TEST(s == refstr);
}

BOOST_AUTO_TEST_CASE(init_ctor__empty)
{
    node n{};
    BOOST_TEST_REQUIRE(n.is_list());
    BOOST_TEST(n.empty());
}

BOOST_AUTO_TEST_CASE(init_ctor__single)
{
    using namespace std::string_literals;
    const auto s1 = "foo"s;

    node n{ s1 };
    BOOST_TEST_REQUIRE(n.is_list());
    BOOST_TEST_REQUIRE(!n.empty());
    BOOST_TEST(n.size() == 1);
    BOOST_TEST(n.at(0).is_string());
    BOOST_TEST(n.at(0).get_string() == s1);
}

BOOST_AUTO_TEST_CASE(init_ctor__multi)
{
    using namespace std::string_literals;
    std::string s1 = "foo", s2 = "bar", s3 = "baz";

    node n{ s1,s2,s3 };
    BOOST_TEST_REQUIRE(n.is_list());
    BOOST_TEST_REQUIRE(!n.empty());
    BOOST_TEST(n.size() == 3);
    BOOST_TEST(n.at(0).is_string());
    BOOST_TEST(n.at(0).get_string() == s1);
    BOOST_TEST(n.at(1).is_string());
    BOOST_TEST(n.at(1).get_string() == s2);
    BOOST_TEST(n.at(2).is_string());
    BOOST_TEST(s3 == n.at(2).get_string());
}

BOOST_AUTO_TEST_CASE(init_ctor__complex)
{
    node n{ "foo",{ "bar", "baz" },{ "foobar" }, "oh my" };
    BOOST_TEST_REQUIRE(n.is_list());
    BOOST_TEST_REQUIRE(n.size() == 4);
    BOOST_TEST(n[0].is_string());
    BOOST_TEST(n[1].is_list());
    BOOST_TEST(n[1].size() == 2);
    BOOST_TEST(n[1][0].is_string());
    BOOST_TEST(n[2].is_list());
    BOOST_TEST(n[2].size() == 1);
    BOOST_TEST(n[3].is_string());
}

BOOST_AUTO_TEST_CASE(copy_ctor)
{
    using namespace std::string_literals;
    node n0{ "foo"s, { "bar"s, "baz"s }, {"foobar"s}, "oh my"s };
    node n1 = n0;

    BOOST_TEST(n0 == n1);
}

BOOST_AUTO_TEST_SUITE_END()

struct accessor_fixture
{
    static constexpr char str_raw[] = "foobar";
    const std::string str = str_raw;
    node str_node;
    const node &str_cnode;

    const std::vector<node> node_vector = { "first", "second", "third" };
    node list_node;
    const node &list_cnode;

    accessor_fixture()
        : str_node(str_raw)
        , str_cnode(str_node)
        , list_node()
        , list_cnode(list_node)
    {
        list_node = node(node_vector.begin(), node_vector.end());
    }
};

constexpr char accessor_fixture::str_raw[];

BOOST_FIXTURE_TEST_SUITE(accessor_tests, accessor_fixture)

using namespace std::string_literals;

BOOST_AUTO_TEST_CASE(string_getters)
{
    BOOST_TEST(str_node.is_string());
    BOOST_TEST(!str_node.get_string().compare(str));
    BOOST_CHECK_THROW(str_node.get_list(), std::domain_error);
    BOOST_TEST_REQUIRE(str_node.try_get_string());
    BOOST_TEST(!str_node.try_get_string()->compare(str));
    BOOST_TEST(!str_node.try_get_list());

    BOOST_TEST(str_cnode.is_string());
    BOOST_TEST(!str_cnode.get_string().compare(str));
    BOOST_CHECK_THROW(str_cnode.get_list(), std::domain_error);
    BOOST_TEST_REQUIRE(str_cnode.try_get_string());
    BOOST_TEST(!str_cnode.try_get_string()->compare(str));
    BOOST_TEST(!str_cnode.try_get_list());
}

BOOST_AUTO_TEST_CASE(list_getters)
{
    BOOST_TEST(list_node.is_list());
    BOOST_TEST(list_node.get_list() == node_vector);
    BOOST_CHECK_THROW(list_node.get_string(), std::domain_error);
    BOOST_TEST_REQUIRE(list_node.try_get_list());
    BOOST_TEST(*list_node.try_get_list() == node_vector);
    BOOST_TEST(!list_node.try_get_string());

    BOOST_TEST(list_cnode.is_list());
    BOOST_TEST(list_cnode.get_list() == node_vector);
    BOOST_CHECK_THROW(list_cnode.get_string(), std::domain_error);
    BOOST_TEST_REQUIRE(list_cnode.try_get_list());
    BOOST_TEST(*list_cnode.try_get_list() == node_vector);
    BOOST_TEST(!list_cnode.try_get_string());
}

BOOST_AUTO_TEST_CASE(list_container_emulation)
{
    BOOST_TEST(list_node.get_list() == node_vector);

    BOOST_TEST(list_node.at(0) == node_vector.at(0));
    BOOST_TEST(list_node.at(1) == node_vector.at(1));
    BOOST_TEST(list_node.at(2) == node_vector.at(2));
    BOOST_TEST(list_cnode.at(0) == node_vector.at(0));
    BOOST_TEST(list_cnode.at(1) == node_vector.at(1));
    BOOST_TEST(list_cnode.at(2) == node_vector.at(2));

    BOOST_CHECK_THROW(list_node.at(3), std::exception);
    BOOST_TEST(list_node.at(0) == list_node[0]);
    BOOST_TEST(list_node.at(1) == list_node[1]);
    BOOST_TEST(list_node.at(2) == list_node[2]);
    BOOST_TEST(list_node.at(0) == list_cnode[0]);
    BOOST_TEST(list_node.at(1) == list_cnode[1]);
    BOOST_TEST(list_node.at(2) == list_cnode[2]);

    BOOST_TEST(list_node.front() == node_vector.front());
    BOOST_TEST(list_cnode.front() == node_vector.front());

    BOOST_TEST(list_node.back() == node_vector.back());
    BOOST_TEST(list_cnode.back() == node_vector.back());

    BOOST_TEST(list_node.empty() == node_vector.empty());
    BOOST_TEST(list_cnode.empty() == node_vector.empty());

    BOOST_TEST(list_node.size() == node_vector.size());
    BOOST_TEST(list_cnode.size() == node_vector.size());

    BOOST_TEST(list_node.max_size() >= list_node.size());
    BOOST_TEST(list_cnode.max_size() >= list_cnode.size());
    BOOST_TEST(list_cnode.max_size() >= list_node.max_size());
}

BOOST_AUTO_TEST_CASE(string_container_emulation)
{
    BOOST_CHECK_THROW(str_node.at(0), std::domain_error);
    BOOST_CHECK_THROW(str_node.at(1), std::domain_error);
    BOOST_CHECK_THROW(str_cnode.at(0), std::domain_error);
    BOOST_CHECK_THROW(str_cnode.at(1), std::domain_error);

    BOOST_CHECK_THROW(str_node[0], std::domain_error);
    BOOST_CHECK_THROW(str_node[1], std::domain_error);
    BOOST_CHECK_THROW(str_cnode[0], std::domain_error);
    BOOST_CHECK_THROW(str_cnode[1], std::domain_error);

    BOOST_CHECK_THROW(str_node.front(), std::domain_error);
    BOOST_CHECK_THROW(str_cnode.front(), std::domain_error);

    BOOST_CHECK_THROW(str_node.back(), std::domain_error);
    BOOST_CHECK_THROW(str_cnode.back(), std::domain_error);

    BOOST_TEST(!str_node.empty());
    BOOST_TEST(!str_cnode.empty());

    BOOST_TEST(str_node.size() == 1);
    BOOST_TEST(str_cnode.size() == 1);

    BOOST_TEST(str_node.max_size() == 1);
    BOOST_TEST(str_cnode.max_size() == 1);
}

BOOST_AUTO_TEST_CASE(explicit_string_conversion)
{
    node::string s(str_cnode);
    BOOST_TEST(s == str_cnode.get_string());
    BOOST_TEST(static_cast<node::string>(str_cnode) == str_cnode.get_string());

    BOOST_CHECK_THROW(static_cast<node::string>(list_cnode), std::domain_error);
}

BOOST_AUTO_TEST_CASE(string_container_iterators)
{
    BOOST_CHECK_THROW(str_node.begin(), std::domain_error);
    BOOST_CHECK_THROW(str_cnode.begin(), std::domain_error);
    BOOST_CHECK_THROW(str_node.cbegin(), std::domain_error);

    BOOST_CHECK_THROW(str_node.end(), std::domain_error);
    BOOST_CHECK_THROW(str_cnode.end(), std::domain_error);
    BOOST_CHECK_THROW(str_node.cend(), std::domain_error);

    BOOST_CHECK_THROW(str_node.rbegin(), std::domain_error);
    BOOST_CHECK_THROW(str_cnode.rbegin(), std::domain_error);
    BOOST_CHECK_THROW(str_node.crbegin(), std::domain_error);

    BOOST_CHECK_THROW(str_node.rend(), std::domain_error);
    BOOST_CHECK_THROW(str_cnode.rend(), std::domain_error);
    BOOST_CHECK_THROW(str_node.crend(), std::domain_error);
}

BOOST_AUTO_TEST_CASE(list_container_iterators)
{
    BOOST_CHECK_EQUAL_COLLECTIONS(list_node.begin(), list_node.end(),
        node_vector.begin(), node_vector.end());
    BOOST_CHECK_EQUAL_COLLECTIONS(list_cnode.begin(), list_cnode.end(),
        node_vector.begin(), node_vector.end());
    BOOST_CHECK_EQUAL_COLLECTIONS(list_cnode.cbegin(), list_cnode.cend(),
        node_vector.begin(), node_vector.end());

    BOOST_CHECK_EQUAL_COLLECTIONS(list_node.rbegin(), list_node.rend(),
        node_vector.rbegin(), node_vector.rend());
    BOOST_CHECK_EQUAL_COLLECTIONS(list_cnode.rbegin(), list_cnode.rend(),
        node_vector.rbegin(), node_vector.rend());
    BOOST_CHECK_EQUAL_COLLECTIONS(list_cnode.crbegin(), list_cnode.crend(),
        node_vector.rbegin(), node_vector.rend());
}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_CASE(string_clear_test)
{
    node s_node("some-str content");
    BOOST_TEST_REQUIRE(s_node.is_string());
    BOOST_TEST_REQUIRE(!s_node.get_string().empty());
    s_node.clear();
    BOOST_TEST(s_node.get_string().empty());
}

BOOST_AUTO_TEST_CASE(string_container_ops_test)
{
    node dummy;
    node s_node("some-str content");
    std::list<node> node_list;

    BOOST_CHECK_THROW(s_node.insert(node::const_iterator(), dummy), std::domain_error);
    BOOST_CHECK_THROW(s_node.insert(node::const_iterator(), std::move(dummy)), std::domain_error);
    BOOST_CHECK_THROW(s_node.insert(node::const_iterator(), 3, dummy), std::domain_error);
    BOOST_CHECK_THROW(s_node.insert(node::const_iterator(), 3, std::move(dummy)), std::domain_error);
    BOOST_CHECK_THROW(s_node.insert(node::const_iterator(), node_list.begin(), node_list.end()), std::domain_error);
    BOOST_CHECK_THROW(s_node.insert(node::const_iterator(), {}), std::domain_error);

    BOOST_CHECK_THROW(s_node.erase(node::const_iterator()), std::domain_error);
    BOOST_CHECK_THROW(s_node.erase(node::const_iterator(), node::const_iterator()), std::domain_error);

    BOOST_CHECK_THROW(s_node.push_back(dummy), std::domain_error);
    BOOST_CHECK_THROW(s_node.push_back(std::move(dummy)), std::domain_error);

    BOOST_CHECK_THROW(s_node.emplace_back(), std::domain_error);
    BOOST_CHECK_THROW(s_node.emplace_back("blublbub"), std::domain_error);

    BOOST_CHECK_THROW(s_node.pop_back(), std::domain_error);

    BOOST_CHECK_THROW(s_node.resize(3), std::domain_error);
    BOOST_CHECK_THROW(s_node.resize(3, dummy), std::domain_error);
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>//
// Aspia Project
// Copyright (C) 2020 Dmitry Chapyshev <dmitry@aspia.ru>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// 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.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

#include "base/files/file_path_watcher.h"

#include "base/logging.h"
#include "build/build_config.h"

namespace base {

FilePathWatcher::~FilePathWatcher()
{
    impl_->cancel();
}

// static
bool FilePathWatcher::recursiveWatchAvailable()
{
#if (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN) || \
    defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_AIX)
    return true;
#else
    // FSEvents isn't available on iOS.
    return false;
#endif
}

FilePathWatcher::PlatformDelegate::PlatformDelegate(std::shared_ptr<TaskRunner> task_runner)
    : task_runner_(std::move(task_runner)),
      cancelled_(false)
{
    // Nothing
}

FilePathWatcher::PlatformDelegate::~PlatformDelegate()
{
    DCHECK(isCancelled());
}

bool FilePathWatcher::watch(const std::filesystem::path& path,
                            bool recursive,
                            const Callback& callback)
{
    DCHECK(path.is_absolute());
    return impl_->watch(path, recursive, callback);
}

} // namespace base
<commit_msg>Fix check.<commit_after>//
// Aspia Project
// Copyright (C) 2020 Dmitry Chapyshev <dmitry@aspia.ru>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// 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.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

#include "base/files/file_path_watcher.h"

#include "base/logging.h"
#include "build/build_config.h"

namespace base {

FilePathWatcher::~FilePathWatcher()
{
    impl_->cancel();
}

// static
bool FilePathWatcher::recursiveWatchAvailable()
{
#if (defined(OS_MAC) && !defined(OS_IOS)) || defined(OS_WIN) || \
    defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_AIX)
    return true;
#else
    // FSEvents isn't available on iOS.
    return false;
#endif
}

FilePathWatcher::PlatformDelegate::PlatformDelegate(std::shared_ptr<TaskRunner> task_runner)
    : task_runner_(std::move(task_runner)),
      cancelled_(false)
{
    // Nothing
}

FilePathWatcher::PlatformDelegate::~PlatformDelegate()
{
    DCHECK(isCancelled());
}

bool FilePathWatcher::watch(const std::filesystem::path& path,
                            bool recursive,
                            const Callback& callback)
{
    DCHECK(path.is_absolute());
    return impl_->watch(path, recursive, callback);
}

} // namespace base
<|endoftext|>


<commit_before>
#include <map>
#include <algorithm>
#include <vector>
#include <random>
#include <ctime>

#include <glbinding/gl/functions.h>
#include <glbinding/gl/extension.h>
#include <glbinding/gl/enum.h>

#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/random.hpp>

#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>

#include <globjects/globjects.h>
#include <globjects/logging.h>
#include <globjects/Texture.h>
#include <globjects/NamedString.h>

#include <globjects/base/File.h>

#include <common/Timer.h>
#include <common/Camera.h>
#include <common/AbstractCoordinateProvider.h>
#include <common/WorldInHandNavigation.h>
#include <common/Context.h>
#include <common/ContextFormat.h>
#include <common/Window.h>
#include <common/WindowEventHandler.h>
#include <common/events.h>

#include "AbstractParticleTechnique.h"

#include "ComputeShaderParticles.h"
#include "FragmentShaderParticles.h"
#include "TransformFeedbackParticles.h"

using namespace gl;
using namespace glm;
using namespace globjects;

class EventHandler : public WindowEventHandler, AbstractCoordinateProvider
{
public:
    EventHandler(int numParticles)
    : m_technique(ParticleTechnique::FragmentShaderTechnique)
    , m_numParticles(numParticles)
    , m_camera(nullptr)
    , m_steps(1)
    , m_nav(nullptr)
    {
        m_timer.setAutoUpdating(false);
        m_timer.start();
    }

    virtual ~EventHandler()
    {
        delete m_nav;
        delete m_camera;
    }

    virtual void initialize(Window & window) override
    {
        WindowEventHandler::initialize(window);

        // Initialize Particle Positions and Attributes

        m_positions.resize(m_numParticles);
        for (int i = 0; i < m_numParticles; ++i)
            m_positions[i] = vec4(sphericalRand<float>(1.f), 1.f);

        m_velocities.resize(m_numParticles);
        for (int i = 0; i < m_numParticles; ++i)
            m_velocities[i] = vec4(0.f);

        m_forces = Texture::createDefault(GL_TEXTURE_3D);

        NamedString::create("/particle-step.inc", new File("data/gpu-particles/particle-step.inc"));

        // initialize camera

        m_camera = new Camera(vec3( 0.f, 1.f,-3.f));
        m_camera->setZNear(1.f);
        m_camera->setZFar(16.f);

        m_nav = new  WorldInHandNavigation();
        m_nav->setCamera(m_camera);
        m_nav->setCoordinateProvider(this);

        // initialize techniques

        if (hasExtension(GLextension::GL_ARB_compute_shader))
            m_techniques[ParticleTechnique::ComputeShaderTechnique] = new ComputeShaderParticles(
                m_positions, m_velocities, *m_forces, *m_camera);
        else
            warning() << "Compute shader based implementation not supported.";

        if (hasExtension(GLextension::GL_ARB_transform_feedback3))
            m_techniques[ParticleTechnique::TransformFeedbackTechnique] = new TransformFeedbackParticles(
                m_positions, m_velocities, *m_forces, *m_camera);
        else
            warning() << "Transform feedback based implementation not supported.";

        m_techniques[ParticleTechnique::FragmentShaderTechnique] = new FragmentShaderParticles(
            m_positions, m_velocities, *m_forces, *m_camera);

        for (auto technique : m_techniques)
            if (technique.second)
                technique.second->initialize();

        reset();
    }

    virtual void framebufferResizeEvent(ResizeEvent & event) override
    {
        glViewport(0, 0, event.width(), event.height());

        m_camera->setViewport(event.size());

        for (auto technique : m_techniques)
            technique.second->resize();
    }

    virtual void paintEvent(PaintEvent & event) override
    {
        WindowEventHandler::paintEvent(event);

        draw();
    }

    void step(const float delta)
    {
        const float delta_stepped = delta / static_cast<float>(m_steps);

        for (int i = 0; i < m_steps; ++i)
            m_techniques[m_technique]->step(delta_stepped);
    }

    void draw()
    {
        const long double elapsed = static_cast<long double>(m_timer.elapsed().count());
        m_timer.update();

        const float delta = static_cast<float>((m_timer.elapsed().count() - elapsed) * 1.0e-9L);

        step(delta); // requires context to be current
        m_techniques[m_technique]->draw(delta);
    }

    void reset(const bool particles = true)
    {
        // initialize 3D Force Field (3D Texture)

        static const ivec3 fdim(5, 5, 5); // this has center axises and allows for random rings etc..

        std::vector<vec3> forces;
        forces.resize(fdim.x * fdim.y * fdim.z);

        srand(static_cast<unsigned int>(time(0)));

        for (int z = 0; z < fdim.z; ++z)
        for (int y = 0; y < fdim.y; ++y)
        for (int x = 0; x < fdim.x; ++x)
        {
            const int i = z *  fdim.x * fdim.y + y * fdim.x + x;
            const vec3 f(sphericalRand<float>(1.0));

            forces[i] = f * (1.f - length(vec3(x, y, z)) / std::sqrt(3.f));
        }

        m_forces->image3D(0, GL_RGB32F, fdim.x, fdim.y, fdim.z, 0, GL_RGB, GL_FLOAT, forces.data());

        if (!particles)
            return;

        m_timer.reset();
        m_timer.update();

        for (auto technique : m_techniques)
            technique.second->reset();
    }

    // EVENT HANDLING

    virtual void keyPressEvent(KeyEvent & event) override
    {
        WindowEventHandler::keyPressEvent(event);

        switch (event.key())
        {
        case GLFW_KEY_C:
            if (m_techniques[ParticleTechnique::ComputeShaderTechnique])
            {
                debug() << "switch to compute shader technique";
                m_technique = ParticleTechnique::ComputeShaderTechnique;
            };
            break;

        case GLFW_KEY_T:
            if (m_techniques[ParticleTechnique::TransformFeedbackTechnique])
            {
                debug() << "switch to transform feedback technique";
                m_technique = ParticleTechnique::TransformFeedbackTechnique;
            }
            break;

        case GLFW_KEY_F:
            debug() << "switch to fragment shader technique";
            m_technique = ParticleTechnique::FragmentShaderTechnique;
            break;

        case GLFW_KEY_P:
            if (m_timer.paused())
            {
                debug() << "timer continue";
                m_timer.start();
            }
            else
            {
                debug() << "timer pause";
                m_timer.pause();
            }
            for (auto technique : m_techniques)
                if (technique.second)
                    technique.second->pause(m_timer.paused());

            break;

        case GLFW_KEY_R:
            reset(event.modifiers() & GLFW_MOD_SHIFT);
            break;

        case GLFW_KEY_MINUS:
            m_steps = max(1, m_steps - 1);
            debug() << "steps = " << m_steps;
            break;

        case GLFW_KEY_EQUAL: // bug? this is plus/add on my keyboard
            ++m_steps;
            debug() << "steps = " << m_steps;
            break;
        }
    }

    virtual void mousePressEvent(MouseEvent & event) override
    {
        switch (event.button())
        {
        case GLFW_MOUSE_BUTTON_LEFT:
            m_nav->rotateBegin(event.pos());
            event.accept();
            break;
        }
    }
    virtual void mouseMoveEvent(MouseEvent & event) override
    {
        switch (m_nav->mode())
        {
        case WorldInHandNavigation::RotateInteraction:
            m_nav->rotateProcess(event.pos());
            event.accept();
            break;

        case WorldInHandNavigation::PanInteraction:
        case WorldInHandNavigation::NoInteraction:
            break;
        }
    }
    virtual void mouseReleaseEvent(MouseEvent & event) override
    {
        switch (event.button())
        {
        case GLFW_MOUSE_BUTTON_LEFT:
            m_nav->rotateEnd();
            event.accept();
            break;
        }
    }

    virtual void scrollEvent(ScrollEvent & event) override
    {
        if (WorldInHandNavigation::NoInteraction != m_nav->mode())
            return;

        m_nav->scaleAtCenter(-event.offset().y * 0.1f);
        event.accept();
    }

    virtual float depthAt(const ivec2 & /*windowCoordinates*/) const override
    {
        return 2.f;
    }

    virtual vec3 objAt(const ivec2 & /*windowCoordinates*/) const override
    {
        return vec3(0.f);
    }
    virtual vec3 objAt(const ivec2 & /*windowCoordinates*/, const float /*depth*/) const override
    {
        return vec3(0.f);
    }
    virtual vec3 objAt(const ivec2 & /*windowCoordinates*/, const float /*depth*/, const mat4 & /*viewProjectionInverted*/) const override
    {
        return vec3(0.f);
    }

protected:

    enum class ParticleTechnique
    {
        ComputeShaderTechnique
    ,   FragmentShaderTechnique
    ,   TransformFeedbackTechnique
    };

    ParticleTechnique m_technique;
    std::map<ParticleTechnique, AbstractParticleTechnique *> m_techniques;

    Timer m_timer;

    int m_numParticles;
    Camera * m_camera;

    std::vector<vec4> m_positions;
    std::vector<vec4> m_velocities;

    int m_steps;

    WorldInHandNavigation * m_nav;

    struct Attribute
    {
        int moep;
    };
    std::vector<Attribute> m_attributes;

    ref_ptr<Texture> m_forces;
};

int main(int argc, char * argv[])
{
    info() << "Usage:";
    info() << "\t" << "ESC" << "\t\t"       << "Close example";
    info() << "\t" << "ALT + Enter" << "\t" << "Toggle fullscreen";
    info() << "\t" << "F11" << "\t\t"       << "Toggle fullscreen";
    info() << "\t" << "F10" << "\t\t"       << "Toggle vertical sync";
    info() << "\t" << "Left Mouse" << "\t"  << "Rotate scene";
    info() << "\t" << "Mouse Wheel" << "\t" << "Zoom scene";
    info() << "\t" << "-" << "\t\t"         << "Reduce steps per frame";
    info() << "\t" << "=" << "\t\t"         << "Increase steps per frame";
    info() << "\t" << "R" << "\t\t"         << "Compute new forces";
    info() << "\t" << "Shift + R" << "\t"   << "Compute new forces and reset particles";
    info() << "\t" << "P" << "\t\t"         << "Toggle pause";
    info() << "\t" << "F" << "\t\t"         << "Particle computation using fragment shader";
    info() << "\t" << "T" << "\t\t"         << "Particle computation using transform feedback";
    info() << "\t" << "C" << "\t\t"         << "Particle computation using compute shader";

    ContextFormat format;
    format.setVersion(3, 3); // minimum required version is 3.3 due to particle drawing using geometry shader.
    format.setProfile(ContextFormat::Profile::Core);

    Window::init();

    int numParticles = 262144;

    if (argc > 1) // assume that the argument is a number
        numParticles = atoi(argv[1]);

    Window window;
    window.setEventHandler(new EventHandler(numParticles));

    if (!window.create(format, "GPU - Particles Example"))
        return 1;

    window.show();

    return MainLoop::run();
}
<commit_msg>not sure if this is a good idea<commit_after>
#include <map>
#include <algorithm>
#include <vector>
#include <random>
#include <ctime>

#include <glbinding/gl/functions.h>
#include <glbinding/gl/extension.h>
#include <glbinding/gl/enum.h>

#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/random.hpp>

#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>

#include <globjects/globjects.h>
#include <globjects/logging.h>
#include <globjects/Texture.h>
#include <globjects/NamedString.h>

#include <globjects/base/File.h>

#include <common/Timer.h>
#include <common/Camera.h>
#include <common/AbstractCoordinateProvider.h>
#include <common/WorldInHandNavigation.h>
#include <common/Context.h>
#include <common/ContextFormat.h>
#include <common/Window.h>
#include <common/WindowEventHandler.h>
#include <common/events.h>

#include "AbstractParticleTechnique.h"

#include "ComputeShaderParticles.h"
#include "FragmentShaderParticles.h"
#include "TransformFeedbackParticles.h"

using namespace gl;
using namespace glm;
using namespace globjects;

class EventHandler : public WindowEventHandler, AbstractCoordinateProvider
{
public:
    EventHandler(int numParticles)
    : m_technique(ParticleTechnique::FragmentShaderTechnique)
    , m_numParticles(numParticles)
    , m_camera(nullptr)
    , m_steps(1)
    , m_nav(nullptr)
    {
        m_timer.setAutoUpdating(false);
        m_timer.start();
    }

    virtual ~EventHandler()
    {
        delete m_nav;
        delete m_camera;
    }

    virtual void initialize(Window & window) override
    {
        WindowEventHandler::initialize(window);

        // Initialize Particle Positions and Attributes

        m_positions.resize(m_numParticles);
        for (int i = 0; i < m_numParticles; ++i)
            m_positions[i] = vec4(sphericalRand<float>(1.f), 1.f);

        m_velocities.resize(m_numParticles);
        for (int i = 0; i < m_numParticles; ++i)
            m_velocities[i] = vec4(0.f);

        m_forces = Texture::createDefault(GL_TEXTURE_3D);

        NamedString::create("/particle-step.inc", new File("data/gpu-particles/particle-step.inc"));

        // initialize camera

        m_camera = new Camera(vec3( 0.f, 1.f,-3.f));
        m_camera->setZNear(1.f);
        m_camera->setZFar(16.f);

        m_nav = new  WorldInHandNavigation();
        m_nav->setCamera(m_camera);
        m_nav->setCoordinateProvider(this);

        // initialize techniques

        if (hasExtension(GLextension::GL_ARB_compute_shader))
            m_techniques[ParticleTechnique::ComputeShaderTechnique] = new ComputeShaderParticles(
                m_positions, m_velocities, *m_forces, *m_camera);
        else
            warning() << "Compute shader based implementation not supported.";

        if (hasExtension(GLextension::GL_ARB_transform_feedback3))
            m_techniques[ParticleTechnique::TransformFeedbackTechnique] = new TransformFeedbackParticles(
                m_positions, m_velocities, *m_forces, *m_camera);
        else
            warning() << "Transform feedback based implementation not supported.";

        m_techniques[ParticleTechnique::FragmentShaderTechnique] = new FragmentShaderParticles(
            m_positions, m_velocities, *m_forces, *m_camera);

        for (auto technique : m_techniques)
            if (technique.second)
                technique.second->initialize();

        reset();
    }

    virtual void framebufferResizeEvent(ResizeEvent & event) override
    {
        glViewport(0, 0, event.width(), event.height());

        m_camera->setViewport(event.size());

        for (auto technique : m_techniques)
            technique.second->resize();
    }

    virtual void paintEvent(PaintEvent & event) override
    {
        WindowEventHandler::paintEvent(event);

        draw();
    }

    void step(const float delta)
    {
        const float delta_stepped = delta / static_cast<float>(m_steps);

        for (int i = 0; i < m_steps; ++i)
            m_techniques[m_technique]->step(delta_stepped);
    }

    void draw()
    {
        const long double elapsed = static_cast<long double>(m_timer.elapsed().count());
        m_timer.update();

        const float delta = static_cast<float>((m_timer.elapsed().count() - elapsed) * 1.0e-9L);

        step(delta); // requires context to be current
        m_techniques[m_technique]->draw(delta);
    }

    void reset(const bool particles = true)
    {
        // initialize 3D Force Field (3D Texture)

        static const ivec3 fdim(8, 8, 8); // this has center axises and allows for random rings etc..

        std::vector<vec3> forces;
        forces.resize(fdim.x * fdim.y * fdim.z);

        srand(static_cast<unsigned int>(time(0)));

        for (int z = 0; z < fdim.z; ++z)
        for (int y = 0; y < fdim.y; ++y)
        for (int x = 0; x < fdim.x; ++x)
        {
            const int i = z *  fdim.x * fdim.y + y * fdim.x + x;
            const vec3 f(sphericalRand<float>(1.0));

            forces[i] = f * (1.f - length(vec3(x, y, z)) / std::sqrt(3.f)) * 10.f;
        }

        m_forces->image3D(0, GL_RGB32F, fdim.x, fdim.y, fdim.z, 0, GL_RGB, GL_FLOAT, forces.data());

        if (!particles)
            return;

        m_timer.reset();
        m_timer.update();

        for (auto technique : m_techniques)
            technique.second->reset();
    }

    // EVENT HANDLING

    virtual void keyPressEvent(KeyEvent & event) override
    {
        WindowEventHandler::keyPressEvent(event);

        switch (event.key())
        {
        case GLFW_KEY_C:
            if (m_techniques[ParticleTechnique::ComputeShaderTechnique])
            {
                debug() << "switch to compute shader technique";
                m_technique = ParticleTechnique::ComputeShaderTechnique;
            };
            break;

        case GLFW_KEY_T:
            if (m_techniques[ParticleTechnique::TransformFeedbackTechnique])
            {
                debug() << "switch to transform feedback technique";
                m_technique = ParticleTechnique::TransformFeedbackTechnique;
            }
            break;

        case GLFW_KEY_F:
            debug() << "switch to fragment shader technique";
            m_technique = ParticleTechnique::FragmentShaderTechnique;
            break;

        case GLFW_KEY_P:
            if (m_timer.paused())
            {
                debug() << "timer continue";
                m_timer.start();
            }
            else
            {
                debug() << "timer pause";
                m_timer.pause();
            }
            for (auto technique : m_techniques)
                if (technique.second)
                    technique.second->pause(m_timer.paused());

            break;

        case GLFW_KEY_R:
            reset(event.modifiers() & GLFW_MOD_SHIFT);
            break;

        case GLFW_KEY_MINUS:
            m_steps = max(1, m_steps - 1);
            debug() << "steps = " << m_steps;
            break;

        case GLFW_KEY_EQUAL: // bug? this is plus/add on my keyboard
            ++m_steps;
            debug() << "steps = " << m_steps;
            break;
        }
    }

    virtual void mousePressEvent(MouseEvent & event) override
    {
        switch (event.button())
        {
        case GLFW_MOUSE_BUTTON_LEFT:
            m_nav->rotateBegin(event.pos());
            event.accept();
            break;
        }
    }
    virtual void mouseMoveEvent(MouseEvent & event) override
    {
        switch (m_nav->mode())
        {
        case WorldInHandNavigation::RotateInteraction:
            m_nav->rotateProcess(event.pos());
            event.accept();
            break;

        case WorldInHandNavigation::PanInteraction:
        case WorldInHandNavigation::NoInteraction:
            break;
        }
    }
    virtual void mouseReleaseEvent(MouseEvent & event) override
    {
        switch (event.button())
        {
        case GLFW_MOUSE_BUTTON_LEFT:
            m_nav->rotateEnd();
            event.accept();
            break;
        }
    }

    virtual void scrollEvent(ScrollEvent & event) override
    {
        if (WorldInHandNavigation::NoInteraction != m_nav->mode())
            return;

        m_nav->scaleAtCenter(-event.offset().y * 0.1f);
        event.accept();
    }

    virtual float depthAt(const ivec2 & /*windowCoordinates*/) const override
    {
        return 2.f;
    }

    virtual vec3 objAt(const ivec2 & /*windowCoordinates*/) const override
    {
        return vec3(0.f);
    }
    virtual vec3 objAt(const ivec2 & /*windowCoordinates*/, const float /*depth*/) const override
    {
        return vec3(0.f);
    }
    virtual vec3 objAt(const ivec2 & /*windowCoordinates*/, const float /*depth*/, const mat4 & /*viewProjectionInverted*/) const override
    {
        return vec3(0.f);
    }

protected:

    enum class ParticleTechnique
    {
        ComputeShaderTechnique
    ,   FragmentShaderTechnique
    ,   TransformFeedbackTechnique
    };

    ParticleTechnique m_technique;
    std::map<ParticleTechnique, AbstractParticleTechnique *> m_techniques;

    Timer m_timer;

    int m_numParticles;
    Camera * m_camera;

    std::vector<vec4> m_positions;
    std::vector<vec4> m_velocities;

    int m_steps;

    WorldInHandNavigation * m_nav;

    struct Attribute
    {
        int moep;
    };
    std::vector<Attribute> m_attributes;

    ref_ptr<Texture> m_forces;
};

int main(int argc, char * argv[])
{
    info() << "Usage:";
    info() << "\t" << "ESC" << "\t\t"       << "Close example";
    info() << "\t" << "ALT + Enter" << "\t" << "Toggle fullscreen";
    info() << "\t" << "F11" << "\t\t"       << "Toggle fullscreen";
    info() << "\t" << "F10" << "\t\t"       << "Toggle vertical sync";
    info() << "\t" << "Left Mouse" << "\t"  << "Rotate scene";
    info() << "\t" << "Mouse Wheel" << "\t" << "Zoom scene";
    info() << "\t" << "-" << "\t\t"         << "Reduce steps per frame";
    info() << "\t" << "=" << "\t\t"         << "Increase steps per frame";
    info() << "\t" << "R" << "\t\t"         << "Compute new forces";
    info() << "\t" << "Shift + R" << "\t"   << "Compute new forces and reset particles";
    info() << "\t" << "P" << "\t\t"         << "Toggle pause";
    info() << "\t" << "F" << "\t\t"         << "Particle computation using fragment shader";
    info() << "\t" << "T" << "\t\t"         << "Particle computation using transform feedback";
    info() << "\t" << "C" << "\t\t"         << "Particle computation using compute shader";

    ContextFormat format;
    format.setVersion(3, 3); // minimum required version is 3.3 due to particle drawing using geometry shader.
    format.setProfile(ContextFormat::Profile::Core);

    Window::init();

    int numParticles = 262144;

    if (argc > 1) // assume that the argument is a number
        numParticles = atoi(argv[1]);

    Window window;
    window.setEventHandler(new EventHandler(numParticles));

    if (!window.create(format, "GPU - Particles Example"))
        return 1;

    window.show();

    return MainLoop::run();
}
<|endoftext|>


<commit_before><commit_msg>add debug info to block writer<commit_after><|endoftext|>


<commit_before>// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#include "mlas.h"
#include "bench_util.h"
#include "core/util/thread_utils.h"

#include <stdexcept>
#include <memory>
#include <numeric>
#include <algorithm>

static const std::vector<std::string> qgemm_arg_names = {"M", "N", "K", "Batch", "Threads"};

void QGEMM(benchmark::State& state, bool pack_b, bool a_is_signed) {
  constexpr bool b_is_signed = true;
  constexpr uint8_t a_zero_point = 29;
  constexpr uint8_t b_zero_point = 179;

  if (state.range(0) <= 0) throw std::invalid_argument("M must greater than 0!");
  if (state.range(1) <= 0) throw std::invalid_argument("N must greater than 0!");
  if (state.range(2) <= 0) throw std::invalid_argument("K must greater than 0!");
  if (state.range(3) <= 0) throw std::invalid_argument("Batch must greater than 0!");
  if (state.range(4) <= 0) throw std::invalid_argument("Threads must greater than 0!");

  const size_t M = static_cast<size_t>(state.range(0));
  const size_t N = static_cast<size_t>(state.range(1));
  const size_t K = static_cast<size_t>(state.range(2));

  const size_t batch = static_cast<size_t>(state.range(3));
  const size_t threads = static_cast<size_t>(state.range(4));

  OrtThreadPoolParams tpo;
  tpo.thread_pool_size = int(threads);
  tpo.auto_set_affinity = true;
  std::unique_ptr<onnxruntime::concurrency::ThreadPool> tp(
      onnxruntime::concurrency::CreateThreadPool(&onnxruntime::Env::Default(),
      tpo, onnxruntime::concurrency::ThreadPoolType::INTRA_OP));

  auto A_holder = RandomVectorUniform<uint8_t>(static_cast<size_t>(M * K * batch), uint8_t(-100), uint8_t(100));
  auto B_holder = RandomVectorUniform<uint8_t>(static_cast<size_t>(N * K * batch), uint8_t(-110), uint8_t(110));
  std::vector<int32_t> C_holder(static_cast<size_t>(M * N * batch));
  std::vector<uint8_t> pack_b_holder;

  size_t packed_b_size = 0;
  if (pack_b) {
    packed_b_size = MlasGemmPackBSize(N, K, a_is_signed, b_is_signed);
    pack_b_holder.resize(packed_b_size * batch);
  }

  MLAS_GEMM_QUANT_SHAPE_PARAMS gemm_shape;

  gemm_shape.M = static_cast<size_t>(M);
  gemm_shape.N = static_cast<size_t>(N);
  gemm_shape.K = static_cast<size_t>(K);
  gemm_shape.AIsSigned = a_is_signed;
  gemm_shape.BIsSigned = b_is_signed;

  std::vector<MLAS_GEMM_QUANT_DATA_PARAMS> gemm_data_vec(batch);
  for (size_t i = 0; i < batch; i++) {
    auto& gemm_params = gemm_data_vec[i];
    gemm_params.lda = gemm_shape.K;
    gemm_params.ZeroPointA = a_zero_point;
    gemm_params.ZeroPointB = &b_zero_point;
    gemm_params.ldc = gemm_shape.N;
    gemm_params.A = A_holder.data() + M * K * i;
    gemm_params.B = B_holder.data() + N * K * i;
    gemm_params.ldb = gemm_shape.N;
    gemm_params.C = C_holder.data() + M * N * i;
    if (pack_b) {
      MlasGemmPackB(N, K, (const uint8_t*)gemm_params.B, N, a_is_signed, b_is_signed, (void*)(pack_b_holder.data() + packed_b_size * i));
      gemm_params.BIsPacked = true;
      gemm_params.B = (void*)(pack_b_holder.data() + packed_b_size * i);
    }
  }
  for (auto _ : state) {
    MlasGemmBatch(gemm_shape, gemm_data_vec.data(), batch, tp.get());
  }
}

static void QGemmSize(benchmark::internal::Benchmark* b) {
  b->ArgNames(qgemm_arg_names);
  // Args for  "M", "N", "K", "Batch",

  b->Args({512, 32128, 768, 1, 1});
  b->Args({512, 32128, 768, 1, 4});
  b->Args({512, 32128, 768, 1, 6});

  b->Args({512, 3072, 768, 1, 1});
  b->Args({512, 3072, 768, 1, 4});
  b->Args({512, 3072, 768, 1, 6});

  b->Args({512, 768, 3072, 1, 1});
  b->Args({512, 768, 3072, 1, 4});
  b->Args({512, 768, 3072, 1, 6});

  b->Args({512, 768, 768, 1, 1});
  b->Args({512, 768, 768, 1, 4});
  b->Args({512, 768, 768, 1, 6});

  b->Args({512, 64, 512, 1, 1});
  b->Args({512, 64, 512, 1, 4});
  b->Args({512, 64, 512, 1, 6});

  b->Args({512, 512, 64, 12, 1});
  b->Args({512, 512, 64, 12, 4});
  b->Args({512, 512, 64, 12, 6});

  b->Args({512, 64, 512, 12, 1});
  b->Args({512, 64, 512, 12, 4});
  b->Args({512, 64, 512, 12, 6});
}

BENCHMARK_CAPTURE(QGEMM, PackB, true, false)->Apply(QGemmSize)->UseRealTime();
BENCHMARK_CAPTURE(QGEMM, NoPackB, false, false)->Apply(QGemmSize)->UseRealTime();
BENCHMARK_CAPTURE(QGEMM, PackB, true, true)->Apply(QGemmSize)->UseRealTime();
BENCHMARK_CAPTURE(QGEMM, NoPackB, false, true)->Apply(QGemmSize)->UseRealTime();<commit_msg>Disable QGEMM, s8 A, s8 B (Packed) bench for AMD64 (#12765)<commit_after>// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#include "mlas.h"
#include "bench_util.h"
#include "core/util/thread_utils.h"

#include <stdexcept>
#include <memory>
#include <numeric>
#include <algorithm>

static const std::vector<std::string> qgemm_arg_names = {"M", "N", "K", "Batch", "Threads"};

void QGEMM(benchmark::State& state, bool pack_b, bool a_is_signed) {
  constexpr bool b_is_signed = true;
  constexpr uint8_t a_zero_point = 29;
  constexpr uint8_t b_zero_point = 179;

  if (state.range(0) <= 0) throw std::invalid_argument("M must greater than 0!");
  if (state.range(1) <= 0) throw std::invalid_argument("N must greater than 0!");
  if (state.range(2) <= 0) throw std::invalid_argument("K must greater than 0!");
  if (state.range(3) <= 0) throw std::invalid_argument("Batch must greater than 0!");
  if (state.range(4) <= 0) throw std::invalid_argument("Threads must greater than 0!");

  const size_t M = static_cast<size_t>(state.range(0));
  const size_t N = static_cast<size_t>(state.range(1));
  const size_t K = static_cast<size_t>(state.range(2));

  const size_t batch = static_cast<size_t>(state.range(3));
  const size_t threads = static_cast<size_t>(state.range(4));

  OrtThreadPoolParams tpo;
  tpo.thread_pool_size = int(threads);
  tpo.auto_set_affinity = true;
  std::unique_ptr<onnxruntime::concurrency::ThreadPool> tp(
      onnxruntime::concurrency::CreateThreadPool(&onnxruntime::Env::Default(),
                                                 tpo, onnxruntime::concurrency::ThreadPoolType::INTRA_OP));

  auto A_holder = RandomVectorUniform<uint8_t>(static_cast<size_t>(M * K * batch), uint8_t(-100), uint8_t(100));
  auto B_holder = RandomVectorUniform<uint8_t>(static_cast<size_t>(N * K * batch), uint8_t(-110), uint8_t(110));
  std::vector<int32_t> C_holder(static_cast<size_t>(M * N * batch));
  std::vector<uint8_t> pack_b_holder;

  size_t packed_b_size = 0;
  if (pack_b) {
    packed_b_size = MlasGemmPackBSize(N, K, a_is_signed, b_is_signed);
    pack_b_holder.resize(packed_b_size * batch);
  }

  MLAS_GEMM_QUANT_SHAPE_PARAMS gemm_shape;

  gemm_shape.M = static_cast<size_t>(M);
  gemm_shape.N = static_cast<size_t>(N);
  gemm_shape.K = static_cast<size_t>(K);
  gemm_shape.AIsSigned = a_is_signed;
  gemm_shape.BIsSigned = b_is_signed;

  std::vector<MLAS_GEMM_QUANT_DATA_PARAMS> gemm_data_vec(batch);
  for (size_t i = 0; i < batch; i++) {
    auto& gemm_params = gemm_data_vec[i];
    gemm_params.lda = gemm_shape.K;
    gemm_params.ZeroPointA = a_zero_point;
    gemm_params.ZeroPointB = &b_zero_point;
    gemm_params.ldc = gemm_shape.N;
    gemm_params.A = A_holder.data() + M * K * i;
    gemm_params.B = B_holder.data() + N * K * i;
    gemm_params.ldb = gemm_shape.N;
    gemm_params.C = C_holder.data() + M * N * i;
    if (pack_b) {
      MlasGemmPackB(N, K, (const uint8_t*)gemm_params.B, N, a_is_signed, b_is_signed, (void*)(pack_b_holder.data() + packed_b_size * i));
      gemm_params.BIsPacked = true;
      gemm_params.B = (void*)(pack_b_holder.data() + packed_b_size * i);
    }
  }
  for (auto _ : state) {
    MlasGemmBatch(gemm_shape, gemm_data_vec.data(), batch, tp.get());
  }
}

static void QGemmSize(benchmark::internal::Benchmark* b) {
  b->ArgNames(qgemm_arg_names);
  // Args for  "M", "N", "K", "Batch", "Threads"

  b->Args({512, 32128, 768, 1, 1});
  b->Args({512, 32128, 768, 1, 4});
  b->Args({512, 32128, 768, 1, 6});

  b->Args({512, 3072, 768, 1, 1});
  b->Args({512, 3072, 768, 1, 4});
  b->Args({512, 3072, 768, 1, 6});

  b->Args({512, 768, 3072, 1, 1});
  b->Args({512, 768, 3072, 1, 4});
  b->Args({512, 768, 3072, 1, 6});

  b->Args({512, 768, 768, 1, 1});
  b->Args({512, 768, 768, 1, 4});
  b->Args({512, 768, 768, 1, 6});

  b->Args({512, 64, 512, 1, 1});
  b->Args({512, 64, 512, 1, 4});
  b->Args({512, 64, 512, 1, 6});

  b->Args({512, 512, 64, 12, 1});
  b->Args({512, 512, 64, 12, 4});
  b->Args({512, 512, 64, 12, 6});

  b->Args({512, 64, 512, 12, 1});
  b->Args({512, 64, 512, 12, 4});
  b->Args({512, 64, 512, 12, 6});
}

BENCHMARK_CAPTURE(QGEMM, UnsignedAPackB, true, false)->Apply(QGemmSize)->UseRealTime();
BENCHMARK_CAPTURE(QGEMM, UnsignedANoPackB, false, false)->Apply(QGemmSize)->UseRealTime();
#if !defined(MLAS_TARGET_AMD64)
// QGEMM is not supported for signed A, signed B (Packed) on AMD64 CPU. The
// benchmark assumes MlasGemmPackBSize return non-zero is not true.
BENCHMARK_CAPTURE(QGEMM, SignedAPackB, true, true)->Apply(QGemmSize)->UseRealTime();
#endif
BENCHMARK_CAPTURE(QGEMM, SignedANoPackB, false, true)->Apply(QGemmSize)->UseRealTime();
<|endoftext|>