<commit_before>
#include "FaceMapper.hpp"
#include "Utilities.hpp"
#include "opencv2/calib3d.hpp"
#include "opencv2/highgui.hpp"

#include <cstdlib>

using namespace std;
using namespace cv;

namespace YerFace {

FaceMapper::FaceMapper(FrameDerivatives *myFrameDerivatives, FaceTracker *myFaceTracker) {
	frameDerivatives = myFrameDerivatives;
	if(frameDerivatives == NULL) {
		throw invalid_argument("frameDerivatives cannot be NULL");
	}
	faceTracker = myFaceTracker;
	if(faceTracker == NULL) {
		throw invalid_argument("faceTracker cannot be NULL");
	}

	markerSeparator = new MarkerSeparator(frameDerivatives, faceTracker);

	markerEyelidLeftTop = new MarkerTracker(EyelidLeftTop, this);
	markerEyelidRightTop = new MarkerTracker(EyelidRightTop, this);
	markerEyelidLeftBottom = new MarkerTracker(EyelidLeftBottom, this);
	markerEyelidRightBottom = new MarkerTracker(EyelidRightBottom, this);

	markerEyebrowLeftInner = new MarkerTracker(EyebrowLeftInner, this);
	markerEyebrowRightInner = new MarkerTracker(EyebrowRightInner, this);
	markerEyebrowLeftMiddle = new MarkerTracker(EyebrowLeftMiddle, this);
	markerEyebrowRightMiddle = new MarkerTracker(EyebrowRightMiddle, this);
	markerEyebrowLeftOuter = new MarkerTracker(EyebrowLeftOuter, this);
	markerEyebrowRightOuter = new MarkerTracker(EyebrowRightOuter, this);

	markerCheekLeft = new MarkerTracker(CheekLeft, this);
	markerCheekRight = new MarkerTracker(CheekRight, this);

	markerJaw = new MarkerTracker(Jaw, this);

	markerLipsLeftCorner = new MarkerTracker(LipsLeftCorner, this);
	markerLipsRightCorner = new MarkerTracker(LipsRightCorner, this);

	markerLipsLeftTop = new MarkerTracker(LipsLeftTop, this);
	markerLipsRightTop = new MarkerTracker(LipsRightTop, this);

	markerLipsLeftBottom = new MarkerTracker(LipsLeftBottom, this);
	markerLipsRightBottom = new MarkerTracker(LipsRightBottom, this);

	fprintf(stderr, "FaceMapper object constructed and ready to go!\n");
}

FaceMapper::~FaceMapper() {
	fprintf(stderr, "FaceMapper object destructing...\n");
	//Make a COPY of the vector, because otherwise it will change size out from under us while we are iterating.
	vector<MarkerTracker *> markerTrackersSnapshot = vector<MarkerTracker *>(*MarkerTracker::getMarkerTrackers());
	size_t markerTrackersCount = markerTrackersSnapshot.size();
	for(size_t i = 0; i < markerTrackersCount; i++) {
		if(markerTrackersSnapshot[i] != NULL) {
			delete markerTrackersSnapshot[i];
		}
	}
	delete markerSeparator;
}

void FaceMapper::processCurrentFrame(void) {

	facialFeatures = faceTracker->getFacialFeatures();
	calculateEyeRects();
	markerSeparator->processCurrentFrame();

	markerJaw->processCurrentFrame();

	markerEyelidLeftTop->processCurrentFrame();
	markerEyelidLeftBottom->processCurrentFrame();
	markerEyebrowLeftInner->processCurrentFrame();
	markerEyebrowLeftMiddle->processCurrentFrame();
	markerEyebrowLeftOuter->processCurrentFrame();
	markerCheekLeft->processCurrentFrame();
	markerLipsLeftCorner->processCurrentFrame();
	markerLipsLeftTop->processCurrentFrame();
	markerLipsLeftBottom->processCurrentFrame();

	markerEyelidRightTop->processCurrentFrame();
	markerEyelidRightBottom->processCurrentFrame();
	markerEyebrowRightInner->processCurrentFrame();
	markerEyebrowRightMiddle->processCurrentFrame();
	markerEyebrowRightOuter->processCurrentFrame();
	markerCheekRight->processCurrentFrame();
	markerLipsRightCorner->processCurrentFrame();
	markerLipsRightTop->processCurrentFrame();
	markerLipsRightBottom->processCurrentFrame();
/*
	//// FIXME FIXME FIXME ////
	FacialCameraModel cameraModel = faceTracker->getFacialCameraModel();
	Mat frame = frameDerivatives->getPreviewFrame();
	FacialPose facialPose = faceTracker->getFacialPose();
	Point3d planePoint = Point3d(facialPose.translationVector.at<double>(0), facialPose.translationVector.at<double>(1), facialPose.translationVector.at<double>(2));
	Mat planeNormalMat = (Mat_<double>(3, 1) << 0.0, 0.0, 1.0);
	planeNormalMat = facialPose.rotationMatrix * planeNormalMat;
	Vec3d planeNormal = Vec3d(planeNormalMat.at<double>(0), planeNormalMat.at<double>(1), planeNormalMat.at<double>(2));

	vector<MarkerTracker *> *markerTrackers = MarkerTracker::getMarkerTrackers();
	size_t markerTrackersCount = (*markerTrackers).size();
	for(size_t i = 0; i < markerTrackersCount; i++) {
		MarkerPoint tempPoint = (*markerTrackers)[i]->getMarkerPoint();
		Mat homogeneousPoint = (Mat_<double>(3,1) << tempPoint.point.x, tempPoint.point.y, 1.0);
		Mat worldPoint = cameraModel.cameraMatrix.inv() * homogeneousPoint;

		Point3d intersection;
		Point3d rayOrigin = Point3d(0,0,0);
		Vec3d rayVector = Vec3d(worldPoint.at<double>(0), worldPoint.at<double>(1), worldPoint.at<double>(2));
		if(!Utilities::rayPlaneIntersection(intersection, rayOrigin, rayVector, planePoint, planeNormal)) {
			fprintf(stderr, "INTERSECTION FAILED!!!\n");
		} else {
			Mat markerMat = (Mat_<double>(3, 1) << intersection.x, intersection.y, intersection.z);
			markerMat = markerMat - facialPose.translationVector;
			markerMat = facialPose.rotationMatrix.inv() * markerMat;

			cout << "****************RECOVERED MARKER POSITION::: " << markerMat << "\n";

			std::vector<Point3d> rayViz3d(2);
			std::vector<Point2d> rayViz2d;
			rayViz3d[0] = intersection;
			rayViz3d[1] = Point3d(markerMat.at<double>(0), markerMat.at<double>(1), markerMat.at<double>(2) + 500);
			Mat tempRotationVector = (Mat_<double>(3, 1) << 0, 0, 0);
			Mat tempTranslationVector = (Mat_<double>(3, 1) << 0, 0, 0);
			projectPoints(rayViz3d, tempRotationVector, tempTranslationVector, cameraModel.cameraMatrix, cameraModel.distortionCoefficients, rayViz2d);
			line(frame, rayViz2d[0], rayViz2d[1], Scalar(0, 0, 255), 1);
		}
	}
	//// END FIXME ////
*/
}

void FaceMapper::renderPreviewHUD(bool verbose) {
	Mat frame = frameDerivatives->getPreviewFrame();
	if(verbose) {
		markerSeparator->renderPreviewHUD(true);

		if(leftEyeRect.set) {
			rectangle(frame, leftEyeRect.rect, Scalar(0, 0, 255));
		}
		if(rightEyeRect.set) {
			rectangle(frame, rightEyeRect.rect, Scalar(0, 0, 255));
		}
	}
	Size frameSize = frame.size();
	double previewRatio = 1.25, previewWidthPercentage = 0.2, previewCenterHeightPercentage = 0.2; // FIXME - magic numbers
	Rect2d previewRect;
	previewRect.width = frameSize.width * previewWidthPercentage;
	previewRect.height = previewRect.width * previewRatio;
	previewRect.x = frameSize.width - previewRect.width;
	previewRect.y = frameSize.height - previewRect.height;
	Point2d previewCenter = Utilities::centerRect(previewRect);
	previewCenter.y -= previewRect.height * previewCenterHeightPercentage;
	double previewPointScale = previewRect.width / 200;
	rectangle(frame, previewRect, Scalar(10, 10, 10), CV_FILLED);
	vector<MarkerTracker *> *markerTrackers = MarkerTracker::getMarkerTrackers();
	size_t markerTrackersCount = (*markerTrackers).size();
	for(size_t i = 0; i < markerTrackersCount; i++) {
		(*markerTrackers)[i]->renderPreviewHUD(verbose);

		MarkerPoint markerPoint = (*markerTrackers)[i]->getMarkerPoint();
		Point2d previewPoint = Point2d(
				(markerPoint.point3d.x * previewPointScale) + previewCenter.x,
				(markerPoint.point3d.y * previewPointScale) + previewCenter.y);
		Utilities::drawX(frame, previewPoint, Scalar(255, 255, 255));
	}
}

FrameDerivatives *FaceMapper::getFrameDerivatives(void) {
	return frameDerivatives;
}

FaceTracker *FaceMapper::getFaceTracker(void) {
	return faceTracker;
}

MarkerSeparator *FaceMapper::getMarkerSeparator(void) {
	return markerSeparator;
}

EyeRect FaceMapper::getLeftEyeRect(void) {
	return leftEyeRect;
}

EyeRect FaceMapper::getRightEyeRect(void) {
	return rightEyeRect;
}

void FaceMapper::calculateEyeRects(void) {
	Point2d pointA, pointB;
	double dist;

	leftEyeRect.set = false;
	rightEyeRect.set = false;

	if(!facialFeatures.set) {
		return;
	}

	pointA = facialFeatures.eyeLeftInnerCorner;
	pointB = facialFeatures.eyeLeftOuterCorner;
	dist = Utilities::lineDistance(pointA, pointB);
	leftEyeRect.rect.x = pointA.x;
	leftEyeRect.rect.y = ((pointA.y + pointB.y) / 2.0) - (dist / 2.0);
	leftEyeRect.rect.width = dist;
	leftEyeRect.rect.height = dist;
	leftEyeRect.rect = Utilities::insetBox(leftEyeRect.rect, 1.25); // FIXME - magic numbers
	leftEyeRect.set = true;

	pointA = facialFeatures.eyeRightOuterCorner;
	pointB = facialFeatures.eyeRightInnerCorner;
	dist = Utilities::lineDistance(pointA, pointB);
	rightEyeRect.rect.x = pointA.x;
	rightEyeRect.rect.y = ((pointA.y + pointB.y) / 2.0) - (dist / 2.0);
	rightEyeRect.rect.width = dist;
	rightEyeRect.rect.height = dist;
	rightEyeRect.rect = Utilities::insetBox(rightEyeRect.rect, 1.25); // FIXME - magic numbers
	rightEyeRect.set = true;
}

}; //namespace YerFace
<commit_msg>remove a bunch of useless experimental code<commit_after>
#include "FaceMapper.hpp"
#include "Utilities.hpp"
#include "opencv2/calib3d.hpp"
#include "opencv2/highgui.hpp"

#include <cstdlib>

using namespace std;
using namespace cv;

namespace YerFace {

FaceMapper::FaceMapper(FrameDerivatives *myFrameDerivatives, FaceTracker *myFaceTracker) {
	frameDerivatives = myFrameDerivatives;
	if(frameDerivatives == NULL) {
		throw invalid_argument("frameDerivatives cannot be NULL");
	}
	faceTracker = myFaceTracker;
	if(faceTracker == NULL) {
		throw invalid_argument("faceTracker cannot be NULL");
	}

	markerSeparator = new MarkerSeparator(frameDerivatives, faceTracker);

	markerEyelidLeftTop = new MarkerTracker(EyelidLeftTop, this);
	markerEyelidRightTop = new MarkerTracker(EyelidRightTop, this);
	markerEyelidLeftBottom = new MarkerTracker(EyelidLeftBottom, this);
	markerEyelidRightBottom = new MarkerTracker(EyelidRightBottom, this);

	markerEyebrowLeftInner = new MarkerTracker(EyebrowLeftInner, this);
	markerEyebrowRightInner = new MarkerTracker(EyebrowRightInner, this);
	markerEyebrowLeftMiddle = new MarkerTracker(EyebrowLeftMiddle, this);
	markerEyebrowRightMiddle = new MarkerTracker(EyebrowRightMiddle, this);
	markerEyebrowLeftOuter = new MarkerTracker(EyebrowLeftOuter, this);
	markerEyebrowRightOuter = new MarkerTracker(EyebrowRightOuter, this);

	markerCheekLeft = new MarkerTracker(CheekLeft, this);
	markerCheekRight = new MarkerTracker(CheekRight, this);

	markerJaw = new MarkerTracker(Jaw, this);

	markerLipsLeftCorner = new MarkerTracker(LipsLeftCorner, this);
	markerLipsRightCorner = new MarkerTracker(LipsRightCorner, this);

	markerLipsLeftTop = new MarkerTracker(LipsLeftTop, this);
	markerLipsRightTop = new MarkerTracker(LipsRightTop, this);

	markerLipsLeftBottom = new MarkerTracker(LipsLeftBottom, this);
	markerLipsRightBottom = new MarkerTracker(LipsRightBottom, this);

	fprintf(stderr, "FaceMapper object constructed and ready to go!\n");
}

FaceMapper::~FaceMapper() {
	fprintf(stderr, "FaceMapper object destructing...\n");
	//Make a COPY of the vector, because otherwise it will change size out from under us while we are iterating.
	vector<MarkerTracker *> markerTrackersSnapshot = vector<MarkerTracker *>(*MarkerTracker::getMarkerTrackers());
	size_t markerTrackersCount = markerTrackersSnapshot.size();
	for(size_t i = 0; i < markerTrackersCount; i++) {
		if(markerTrackersSnapshot[i] != NULL) {
			delete markerTrackersSnapshot[i];
		}
	}
	delete markerSeparator;
}

void FaceMapper::processCurrentFrame(void) {

	facialFeatures = faceTracker->getFacialFeatures();
	calculateEyeRects();
	markerSeparator->processCurrentFrame();

	markerJaw->processCurrentFrame();

	markerEyelidLeftTop->processCurrentFrame();
	markerEyelidLeftBottom->processCurrentFrame();
	markerEyebrowLeftInner->processCurrentFrame();
	markerEyebrowLeftMiddle->processCurrentFrame();
	markerEyebrowLeftOuter->processCurrentFrame();
	markerCheekLeft->processCurrentFrame();
	markerLipsLeftCorner->processCurrentFrame();
	markerLipsLeftTop->processCurrentFrame();
	markerLipsLeftBottom->processCurrentFrame();

	markerEyelidRightTop->processCurrentFrame();
	markerEyelidRightBottom->processCurrentFrame();
	markerEyebrowRightInner->processCurrentFrame();
	markerEyebrowRightMiddle->processCurrentFrame();
	markerEyebrowRightOuter->processCurrentFrame();
	markerCheekRight->processCurrentFrame();
	markerLipsRightCorner->processCurrentFrame();
	markerLipsRightTop->processCurrentFrame();
	markerLipsRightBottom->processCurrentFrame();
}

void FaceMapper::renderPreviewHUD(bool verbose) {
	Mat frame = frameDerivatives->getPreviewFrame();
	if(verbose) {
		markerSeparator->renderPreviewHUD(true);

		if(leftEyeRect.set) {
			rectangle(frame, leftEyeRect.rect, Scalar(0, 0, 255));
		}
		if(rightEyeRect.set) {
			rectangle(frame, rightEyeRect.rect, Scalar(0, 0, 255));
		}
	}
	Size frameSize = frame.size();
	double previewRatio = 1.25, previewWidthPercentage = 0.2, previewCenterHeightPercentage = 0.2; // FIXME - magic numbers
	Rect2d previewRect;
	previewRect.width = frameSize.width * previewWidthPercentage;
	previewRect.height = previewRect.width * previewRatio;
	previewRect.x = frameSize.width - previewRect.width;
	previewRect.y = frameSize.height - previewRect.height;
	Point2d previewCenter = Utilities::centerRect(previewRect);
	previewCenter.y -= previewRect.height * previewCenterHeightPercentage;
	double previewPointScale = previewRect.width / 200;
	rectangle(frame, previewRect, Scalar(10, 10, 10), CV_FILLED);
	vector<MarkerTracker *> *markerTrackers = MarkerTracker::getMarkerTrackers();
	size_t markerTrackersCount = (*markerTrackers).size();
	for(size_t i = 0; i < markerTrackersCount; i++) {
		(*markerTrackers)[i]->renderPreviewHUD(verbose);

		MarkerPoint markerPoint = (*markerTrackers)[i]->getMarkerPoint();
		Point2d previewPoint = Point2d(
				(markerPoint.point3d.x * previewPointScale) + previewCenter.x,
				(markerPoint.point3d.y * previewPointScale) + previewCenter.y);
		Utilities::drawX(frame, previewPoint, Scalar(255, 255, 255));
	}
}

FrameDerivatives *FaceMapper::getFrameDerivatives(void) {
	return frameDerivatives;
}

FaceTracker *FaceMapper::getFaceTracker(void) {
	return faceTracker;
}

MarkerSeparator *FaceMapper::getMarkerSeparator(void) {
	return markerSeparator;
}

EyeRect FaceMapper::getLeftEyeRect(void) {
	return leftEyeRect;
}

EyeRect FaceMapper::getRightEyeRect(void) {
	return rightEyeRect;
}

void FaceMapper::calculateEyeRects(void) {
	Point2d pointA, pointB;
	double dist;

	leftEyeRect.set = false;
	rightEyeRect.set = false;

	if(!facialFeatures.set) {
		return;
	}

	pointA = facialFeatures.eyeLeftInnerCorner;
	pointB = facialFeatures.eyeLeftOuterCorner;
	dist = Utilities::lineDistance(pointA, pointB);
	leftEyeRect.rect.x = pointA.x;
	leftEyeRect.rect.y = ((pointA.y + pointB.y) / 2.0) - (dist / 2.0);
	leftEyeRect.rect.width = dist;
	leftEyeRect.rect.height = dist;
	leftEyeRect.rect = Utilities::insetBox(leftEyeRect.rect, 1.25); // FIXME - magic numbers
	leftEyeRect.set = true;

	pointA = facialFeatures.eyeRightOuterCorner;
	pointB = facialFeatures.eyeRightInnerCorner;
	dist = Utilities::lineDistance(pointA, pointB);
	rightEyeRect.rect.x = pointA.x;
	rightEyeRect.rect.y = ((pointA.y + pointB.y) / 2.0) - (dist / 2.0);
	rightEyeRect.rect.width = dist;
	rightEyeRect.rect.height = dist;
	rightEyeRect.rect = Utilities::insetBox(rightEyeRect.rect, 1.25); // FIXME - magic numbers
	rightEyeRect.set = true;
}

}; //namespace YerFace
<|endoftext|>


<commit_before>#include "GameObject.h"

void GameObject::load(const int x, const int y, const int width, const int height) {
	m_iX = x;
	m_iY = y;
	m_iWidth = width;
	m_iHeight = height;
}

void GameObject::setTexture(const std::string textureID, int nbFrames) {
	m_iCurrentRow = 1;
	m_iCurrentFrame = 1;
	m_iNbFrames = nbFrames;
	m_sTextureID = textureID;
}

void GameObject::setTextureRow(const int currentRow) {
	m_iCurrentRow = currentRow;
}

void GameObject::update() {

}

void GameObject::render() {

}

void GameObject::clean() {

}

<commit_msg>Frames updated in the GameObject::update method<commit_after>#include "GameObject.h"

void GameObject::load(const int x, const int y, const int width, const int height) {
	m_iX = x;
	m_iY = y;
	m_iWidth = width;
	m_iHeight = height;
}

void GameObject::setTexture(const std::string textureID, int nbFrames) {
	m_iCurrentRow = 1;
	m_iCurrentFrame = 1;
	m_iNbFrames = nbFrames;
	m_sTextureID = textureID;
}

void GameObject::setTextureRow(const int currentRow) {
	m_iCurrentRow = currentRow;
}

void GameObject::update() {
	m_iCurrentFrame = int(((SDL_GetTicks() / 100) % m_iNbFrames));
}

void GameObject::render() {

}

void GameObject::clean() {

}

<|endoftext|>


<commit_before>/*
 * Unit tests for libkvkontakte.
 * Copyright (C) 2015  Alexander Potashev <aspotashev@gmail.com>
 *
 * 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 2 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, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "test_userinfo.h"

#include <libkvkontakte/userinfofulljob.h>

#include <qtest_kde.h>

#include <QtCore/QList>

using namespace Vkontakte;

TestUserInfo::TestUserInfo()
    : VkTestBase()
{
}

void TestUserInfo::initTestCase()
{
    authenticate();
}

void TestUserInfo::testUserInfoJob()
{
    Vkontakte::UserInfoJob* const job = new Vkontakte::UserInfoJob(
        accessToken(), 1);

    job->exec();

    QList<UserInfoPtr> res = job->userInfo();
    QCOMPARE(res.size(), 1);

    UserInfoPtr user = res.first();
    QCOMPARE(user->domain(), QString("durov"));
    QCOMPARE(user->firstName(), QString::fromUtf8("Павел"));
}

void TestUserInfo::testUserInfoFullJob()
{
    Vkontakte::UserInfoFullJob* const job = new Vkontakte::UserInfoFullJob(
        accessToken(), 1, true, true);

    job->exec();

    QList<UserInfoPtr> res = job->userInfo();
    QCOMPARE(res.size(), 1);

    UserInfoPtr user = res.first();
    QCOMPARE(user->domain(), QString("durov"));
    QCOMPARE(user->firstName(), QString::fromUtf8("Павел"));
    QCOMPARE(user->countryString(), QString::fromUtf8("Россия"));
    QCOMPARE(user->cityString(), QString::fromUtf8("Санкт-Петербург"));
}

QTEST_KDEMAIN(TestUserInfo, GUI)
#include "test_userinfo.moc"
<commit_msg>test_userinfo: Verify successful completion of jobs<commit_after>/*
 * Unit tests for libkvkontakte.
 * Copyright (C) 2015  Alexander Potashev <aspotashev@gmail.com>
 *
 * 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 2 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, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "test_userinfo.h"

#include <libkvkontakte/userinfofulljob.h>

#include <qtest_kde.h>

#include <QtCore/QList>

using namespace Vkontakte;

TestUserInfo::TestUserInfo()
    : VkTestBase()
{
}

void TestUserInfo::initTestCase()
{
    authenticate();
}

void TestUserInfo::testUserInfoJob()
{
    Vkontakte::UserInfoJob* const job = new Vkontakte::UserInfoJob(
        accessToken(), 1);
    job->exec();
    QVERIFY(!job->error());

    QList<UserInfoPtr> res = job->userInfo();
    QCOMPARE(res.size(), 1);

    UserInfoPtr user = res.first();
    QCOMPARE(user->domain(), QString("durov"));
    QCOMPARE(user->firstName(), QString::fromUtf8("Павел"));
}

void TestUserInfo::testUserInfoFullJob()
{
    Vkontakte::UserInfoFullJob* const job = new Vkontakte::UserInfoFullJob(
        accessToken(), 1, true, true);
    job->exec();
    QVERIFY(!job->error());

    QList<UserInfoPtr> res = job->userInfo();
    QCOMPARE(res.size(), 1);

    UserInfoPtr user = res.first();
    QCOMPARE(user->domain(), QString("durov"));
    QCOMPARE(user->firstName(), QString::fromUtf8("Павел"));
    QCOMPARE(user->countryString(), QString::fromUtf8("Россия"));
    QCOMPARE(user->cityString(), QString::fromUtf8("Санкт-Петербург"));
}

QTEST_KDEMAIN(TestUserInfo, GUI)
#include "test_userinfo.moc"
<|endoftext|>


<commit_before>#include "x86_64-Codegen.h"
#include "ASTNode.h"
#include "lib/Runtime.h"
#include "Internal.h"
#include <stdexcept>
#include <vector>
using namespace std;

#define __ m_Asm->
#define e__ entry_asm->

namespace snow {
namespace x86_64 {
	// stack_frame->`member'
	#define GET_STACK(member) (Address(rbp, (-(int)sizeof(StackFrame))+(int)offsetof(StackFrame, member)))

	// temporaries[id]
	#define GET_TEMPORARY(id) (Address(rbp, (-(int)sizeof(StackFrame))-(sizeof(VALUE)*(id+1))))

	// reg[index] (reg must contain a pointer to an array of values)
	#define GET_ARRAY_PTR(reg, index) (Address((reg), index * sizeof(VALUE)))

	static const Register* arg_regs[] = { &rdi, &rsi, &rdx, &rcx, &r8, &r9 };
	static const uint64_t num_arg_regs = 6;

	Codegen::Codegen(ast::FunctionDefinition& def) :
		snow::Codegen(def),
		m_NumLocals(0),
		m_NumStackArguments(0),
		m_NumTemporaries(0) {
		m_LocalMap = new LocalMap;
		m_Asm = new x86_64::Assembler;
		m_Return = new Label;
	}

	uint64_t Codegen::reserve_temporary() {
		if (m_FreeTemporaries.size() > 0) {
			uint64_t t = m_FreeTemporaries.back();
			m_FreeTemporaries.pop_back();
			return t;
		}
		return m_NumTemporaries++;
	}

	void Codegen::free_temporary(uint64_t id) {
		m_FreeTemporaries.push_back(id);
	}

	void Codegen::get_local(uint64_t id, const Register& reg) {
		__ mov(GET_STACK(locals), reg);
		__ mov(GET_ARRAY_PTR(reg, id), reg);
	}

	void Codegen::set_local(const Register& reg, uint64_t id, const Register& tmp) {
		assert(reg != tmp && "Cannot use source register as temporary storage!");
		__ mov(GET_STACK(locals), tmp);
		__ mov(reg, GET_ARRAY_PTR(tmp, id));
	}

	Handle<CompiledCode> Codegen::compile() {
		RefPtr<x86_64::Assembler> entry_asm = new x86_64::Assembler;
		__ subasm(entry_asm);

		if (m_Def.arguments.size() > 0) {
			__ comment("copy arguments to locals");
			__ mov(GET_STACK(arguments), r8);
			__ mov(GET_STACK(locals), r9);
			size_t i = 0;
			for each (iter, m_Def.arguments) {
				auto local = m_LocalMap->define_local((*iter)->name);
				__ mov(GET_ARRAY_PTR(r8, i), rax);
				__ mov(rax, GET_ARRAY_PTR(r9, local));
				++i;
			}
		}

		__ comment("function body");
		compile(*m_Def.sequence);

		uint64_t return_temporary = reserve_temporary();
		__ comment("function exit");
		__ bind(m_Return);
		__ mov(rax, GET_TEMPORARY(return_temporary));
		__ call("snow_leave_scope");
		__ mov(GET_TEMPORARY(return_temporary), rax);
		__ leave();
		__ ret();

		// Compile the function entry, now that we know all the locals and
		// temporaries.
		{
			e__ comment("function entry");
			int stack_size = sizeof(StackFrame) + sizeof(VALUE)*(m_NumTemporaries + m_NumStackArguments);
			// maintain 16-byte stack alignment
			stack_size += stack_size % 16;
			e__ enter(stack_size);

			e__ mov(rbp, rsi);
			e__ sub(sizeof(StackFrame), rsi);
			e__ call("snow_enter_scope");
		}

		Handle<CompiledCode> code = __ compile();
		code->set_local_map(m_LocalMap);
		for each (iter, m_Related) {
			code->add_related(*iter);
		}
		return code;
	}

	void Codegen::compile(ast::Literal& literal) {
		__ comment(std::string("literal: `")  + literal.string + std::string("'"));
		using ast::Literal;

		const char* str = literal.string.c_str();

		VALUE val = nil();

		switch (literal.type) {
			case Literal::INTEGER_DEC_TYPE:
				val = value(strtoll(str, NULL, 10));
				break;
			case Literal::INTEGER_HEX_TYPE:
				val = value(strtoll(str, NULL, 16));
				break;
			case Literal::INTEGER_BIN_TYPE:
				val = value(strtoll(str, NULL, 2));
				break;
			case Literal::FLOAT_TYPE:
				// TODO: Doubles
				val = value(strtof(str, NULL));
				break;
			case Literal::STRING_TYPE:
				val = create_string(str);
				break;
			case Literal::TRUE_TYPE:
				val = value(true);
				break;
			case Literal::FALSE_TYPE:
				val = value(false);
				break;
			case Literal::NIL_TYPE:
				val = nil();
                break;
		}

		__ mov(val, rax);
	}

	void Codegen::compile(ast::Identifier& id) {
		__ comment(std::string("identifier: `") + id.name + std::string("'"));
		if (m_LocalMap->has_local(id.name)) {
			// It's a local from current scope...
			get_local(m_LocalMap->local(id.name), rax);
		} else {
			// THE PAIN! It's from a parent scope...
			__ mov(rbp, rdi);
			__ sub(sizeof(StackFrame), rdi);
			// TODO/XXX: Symbol storage -- id.name is freed at some point.
			__ mov(id.name.c_str(), rsi);
			__ mov(id.quiet, rdx);
			__ call("snow_get_local");
		}
	}

	void Codegen::compile(ast::Sequence& seq) {
		for each (iter, seq.nodes) {
			(*iter)->compile(*this);
		}
	}

	void Codegen::compile(ast::FunctionDefinition& def) {
		__ comment("function definition");
		RefPtr<Codegen> codegen = new Codegen(def);
		Handle<CompiledCode> code = codegen->compile();
		m_Related.push_back(code);
		VALUE func = new(kMalloc) Function(*code);
		__ mov(func, rdi);
		__ mov(GET_STACK(scope), rsi);
		__ call("snow_set_parent_scope");
		__ mov(func, rax);
	}

	void Codegen::compile(ast::Return& ret) {
		__ comment("return");
		if (ret.expression)
			ret.expression->compile(*this);
		else
			__ clear(rax);
		__ jmp(m_Return);
	}

	void Codegen::compile(ast::Assignment& assign) {
		uint64_t l;
		if (m_LocalMap->has_local(assign.identifier->name))
			l = m_LocalMap->local(assign.identifier->name);
		else
			l = m_LocalMap->define_local(assign.identifier->name);

		assign.expression->compile(*this);
		__ comment(std::string("assignment: ") + assign.identifier->name);
		set_local(rax, l);
	}

	void Codegen::compile(ast::IfCondition& cond) {
		RefPtr<Label> test_cond = new Label;
		RefPtr<Label> after = new Label;

		__ bind(test_cond);
		__ comment("if cond");
		cond.expression->compile(*this);
		__ mov(rax, rdi);
		__ call("snow_eval_truth");
		__ cmp(0, rax);
		__ j(CC_EQUAL, after);
		__ comment("if body");
		cond.if_true->compile(*this);
		__ bind(after);
	}

	void Codegen::compile(ast::IfElseCondition& cond) {
		RefPtr<Label> test_cond = new Label;
		RefPtr<Label> if_true = new Label;
		RefPtr<Label> if_false = new Label;
		RefPtr<Label> after = new Label;

		__ bind(test_cond);
		__ comment("if-else cond");
		cond.expression->compile(*this);
		__ mov(rax, rdi);
		__ call("snow_eval_truth");
		__ cmp(0, rax);
		__ j(CC_EQUAL, if_false);
		__ bind(if_true);
		__ comment("if true");
		cond.if_true->compile(*this);
		__ jmp(after);
		__ bind(if_false);
		__ comment("if false");
		cond.if_false->compile(*this);
		__ bind(after);
	}

	void Codegen::compile(ast::Call& call) {
		auto self_tmp = reserve_temporary();

		__ comment("self for call");
		call.self->compile(*this);
		__ mov(rax, GET_TEMPORARY(self_tmp));

		// evaluate arguments and store temporaries
		auto num_args = call.arguments->length();
		uint64_t args_tmp[num_args];
		size_t i = 0;
		for each (arg_iter, call.arguments->nodes) {
			args_tmp[i] = reserve_temporary();
			__ comment(string_printf("argument %d", i));
			(*arg_iter)->compile(*this);
			__ mov(rax, GET_TEMPORARY(args_tmp[i]));
			++i;
		}

		auto function_tmp = self_tmp;
		if (call.member) {
			__ comment("method call");
			function_tmp = reserve_temporary();
			__ mov(GET_TEMPORARY(self_tmp), rdi);
			__ mov(call.member->name.c_str(), rsi);
			__ call("snow_get");
			__ mov(rax, GET_TEMPORARY(function_tmp));
			__ mov(GET_TEMPORARY(self_tmp), rdi);
		} else {
			__ comment("closure call");
			__ clear(rdi);         // "self" is NULL for closures
		}

		__ mov(GET_TEMPORARY(function_tmp), rsi);
		__ mov(num_args, rdx);

		for (size_t i = 0; i < num_args; ++i) {
			const size_t arg_offset = i + 3;

			if (arg_offset < num_arg_regs) {
				__ mov(GET_TEMPORARY(args_tmp[i]), *arg_regs[arg_offset]);
			} else {
				const size_t stack_offset = arg_offset - num_arg_regs;
				if (m_NumStackArguments < stack_offset)
					m_NumStackArguments = stack_offset;
				__ mov(GET_TEMPORARY(args_tmp[i]), rax);
				// XXX: Can this be done without SIB?
				__ mov(stack_offset, rbx);
				__ mov(rax, SIB(rsp, rbx, SIB::SCALE_8));
			}

			free_temporary(args_tmp[i]);
		}

		if (self_tmp == function_tmp)
			free_temporary(self_tmp);
		else {
			free_temporary(self_tmp);
			free_temporary(function_tmp);
		}

		// finally!
		__ clear(rax);
		__ call("snow_call");
	}

	void Codegen::compile(ast::Get& get) {
		__ comment("get `" + get.member->name + "'");
		get.self->compile(*this);
		__ mov(rax, rdi);
		__ mov(get.member->name.c_str(), rsi);
		__ call("snow_get");
	}

	void Codegen::compile(ast::Set& set) {
		__ comment("set `" + set.member->name + "'");
		set.expression->compile(*this);
		auto tmp = reserve_temporary();
		__ mov(rax, GET_TEMPORARY(tmp));
		set.self->compile(*this);
		__ mov(rax, rdi);
		__ mov(set.member->name.c_str(), rsi);
		__ mov(GET_TEMPORARY(tmp), rdx);
		__ call("snow_set");
		free_temporary(tmp);
	}

	void Codegen::compile(ast::Loop& loop) {
		RefPtr<Label> test_cond = new Label;
		RefPtr<Label> body = new Label;
		RefPtr<Label> after = new Label;

		__ bind(test_cond);
		__ comment("loop cond");
		loop.expression->compile(*this);
		__ mov(rax, rdi);
		__ call("snow_eval_truth");
		__ cmp(0, rax);
		__ j(CC_EQUAL, after);
		__ bind(body);
		__ comment("loop body");
		loop.while_true->compile(*this);
		__ jmp(test_cond);
		__ bind(after);
	}

	void Codegen::compile(ast::Self&) {
		__ mov(GET_STACK(self), rax);
	}

	void Codegen::compile(ast::It&) {
		__ mov(GET_STACK(it), rax);
	}
}
}
<commit_msg>string literals are now allocated by the kMalloc allocator, so they won't ever be deleted.<commit_after>#include "x86_64-Codegen.h"
#include "ASTNode.h"
#include "lib/Runtime.h"
#include "lib/SnowString.h"
#include "Internal.h"
#include <stdexcept>
#include <vector>
using namespace std;

#define __ m_Asm->
#define e__ entry_asm->

namespace snow {
namespace x86_64 {
	// stack_frame->`member'
	#define GET_STACK(member) (Address(rbp, (-(int)sizeof(StackFrame))+(int)offsetof(StackFrame, member)))

	// temporaries[id]
	#define GET_TEMPORARY(id) (Address(rbp, (-(int)sizeof(StackFrame))-(sizeof(VALUE)*(id+1))))

	// reg[index] (reg must contain a pointer to an array of values)
	#define GET_ARRAY_PTR(reg, index) (Address((reg), index * sizeof(VALUE)))

	static const Register* arg_regs[] = { &rdi, &rsi, &rdx, &rcx, &r8, &r9 };
	static const uint64_t num_arg_regs = 6;

	Codegen::Codegen(ast::FunctionDefinition& def) :
		snow::Codegen(def),
		m_NumLocals(0),
		m_NumStackArguments(0),
		m_NumTemporaries(0) {
		m_LocalMap = new LocalMap;
		m_Asm = new x86_64::Assembler;
		m_Return = new Label;
	}

	uint64_t Codegen::reserve_temporary() {
		if (m_FreeTemporaries.size() > 0) {
			uint64_t t = m_FreeTemporaries.back();
			m_FreeTemporaries.pop_back();
			return t;
		}
		return m_NumTemporaries++;
	}

	void Codegen::free_temporary(uint64_t id) {
		m_FreeTemporaries.push_back(id);
	}

	void Codegen::get_local(uint64_t id, const Register& reg) {
		__ mov(GET_STACK(locals), reg);
		__ mov(GET_ARRAY_PTR(reg, id), reg);
	}

	void Codegen::set_local(const Register& reg, uint64_t id, const Register& tmp) {
		assert(reg != tmp && "Cannot use source register as temporary storage!");
		__ mov(GET_STACK(locals), tmp);
		__ mov(reg, GET_ARRAY_PTR(tmp, id));
	}

	Handle<CompiledCode> Codegen::compile() {
		RefPtr<x86_64::Assembler> entry_asm = new x86_64::Assembler;
		__ subasm(entry_asm);

		if (m_Def.arguments.size() > 0) {
			__ comment("copy arguments to locals");
			__ mov(GET_STACK(arguments), r8);
			__ mov(GET_STACK(locals), r9);
			size_t i = 0;
			for each (iter, m_Def.arguments) {
				auto local = m_LocalMap->define_local((*iter)->name);
				__ mov(GET_ARRAY_PTR(r8, i), rax);
				__ mov(rax, GET_ARRAY_PTR(r9, local));
				++i;
			}
		}

		__ comment("function body");
		compile(*m_Def.sequence);

		uint64_t return_temporary = reserve_temporary();
		__ comment("function exit");
		__ bind(m_Return);
		__ mov(rax, GET_TEMPORARY(return_temporary));
		__ call("snow_leave_scope");
		__ mov(GET_TEMPORARY(return_temporary), rax);
		__ leave();
		__ ret();

		// Compile the function entry, now that we know all the locals and
		// temporaries.
		{
			e__ comment("function entry");
			int stack_size = sizeof(StackFrame) + sizeof(VALUE)*(m_NumTemporaries + m_NumStackArguments);
			// maintain 16-byte stack alignment
			stack_size += stack_size % 16;
			e__ enter(stack_size);

			e__ mov(rbp, rsi);
			e__ sub(sizeof(StackFrame), rsi);
			e__ call("snow_enter_scope");
		}

		Handle<CompiledCode> code = __ compile();
		code->set_local_map(m_LocalMap);
		for each (iter, m_Related) {
			code->add_related(*iter);
		}
		return code;
	}

	void Codegen::compile(ast::Literal& literal) {
		__ comment(std::string("literal: `")  + literal.string + std::string("'"));
		using ast::Literal;

		const char* str = literal.string.c_str();

		VALUE val = nil();

		switch (literal.type) {
			case Literal::INTEGER_DEC_TYPE:
				val = value(strtoll(str, NULL, 10));
				break;
			case Literal::INTEGER_HEX_TYPE:
				val = value(strtoll(str, NULL, 16));
				break;
			case Literal::INTEGER_BIN_TYPE:
				val = value(strtoll(str, NULL, 2));
				break;
			case Literal::FLOAT_TYPE:
				// TODO: Doubles
				val = value(strtof(str, NULL));
				break;
			case Literal::STRING_TYPE:
				val = new(kMalloc) String(str);
				break;
			case Literal::TRUE_TYPE:
				val = value(true);
				break;
			case Literal::FALSE_TYPE:
				val = value(false);
				break;
			case Literal::NIL_TYPE:
				val = nil();
                break;
		}

		__ mov(val, rax);
	}

	void Codegen::compile(ast::Identifier& id) {
		__ comment(std::string("identifier: `") + id.name + std::string("'"));
		if (m_LocalMap->has_local(id.name)) {
			// It's a local from current scope...
			get_local(m_LocalMap->local(id.name), rax);
		} else {
			// THE PAIN! It's from a parent scope...
			__ mov(rbp, rdi);
			__ sub(sizeof(StackFrame), rdi);
			// TODO/XXX: Symbol storage -- id.name is freed at some point.
			__ mov(id.name.c_str(), rsi);
			__ mov(id.quiet, rdx);
			__ call("snow_get_local");
		}
	}

	void Codegen::compile(ast::Sequence& seq) {
		for each (iter, seq.nodes) {
			(*iter)->compile(*this);
		}
	}

	void Codegen::compile(ast::FunctionDefinition& def) {
		__ comment("function definition");
		RefPtr<Codegen> codegen = new Codegen(def);
		Handle<CompiledCode> code = codegen->compile();
		m_Related.push_back(code);
		VALUE func = new(kMalloc) Function(*code);
		__ mov(func, rdi);
		__ mov(GET_STACK(scope), rsi);
		__ call("snow_set_parent_scope");
		__ mov(func, rax);
	}

	void Codegen::compile(ast::Return& ret) {
		__ comment("return");
		if (ret.expression)
			ret.expression->compile(*this);
		else
			__ clear(rax);
		__ jmp(m_Return);
	}

	void Codegen::compile(ast::Assignment& assign) {
		uint64_t l;
		if (m_LocalMap->has_local(assign.identifier->name))
			l = m_LocalMap->local(assign.identifier->name);
		else
			l = m_LocalMap->define_local(assign.identifier->name);

		assign.expression->compile(*this);
		__ comment(std::string("assignment: ") + assign.identifier->name);
		set_local(rax, l);
	}

	void Codegen::compile(ast::IfCondition& cond) {
		RefPtr<Label> test_cond = new Label;
		RefPtr<Label> after = new Label;

		__ bind(test_cond);
		__ comment("if cond");
		cond.expression->compile(*this);
		__ mov(rax, rdi);
		__ call("snow_eval_truth");
		__ cmp(0, rax);
		__ j(CC_EQUAL, after);
		__ comment("if body");
		cond.if_true->compile(*this);
		__ bind(after);
	}

	void Codegen::compile(ast::IfElseCondition& cond) {
		RefPtr<Label> test_cond = new Label;
		RefPtr<Label> if_true = new Label;
		RefPtr<Label> if_false = new Label;
		RefPtr<Label> after = new Label;

		__ bind(test_cond);
		__ comment("if-else cond");
		cond.expression->compile(*this);
		__ mov(rax, rdi);
		__ call("snow_eval_truth");
		__ cmp(0, rax);
		__ j(CC_EQUAL, if_false);
		__ bind(if_true);
		__ comment("if true");
		cond.if_true->compile(*this);
		__ jmp(after);
		__ bind(if_false);
		__ comment("if false");
		cond.if_false->compile(*this);
		__ bind(after);
	}

	void Codegen::compile(ast::Call& call) {
		auto self_tmp = reserve_temporary();

		__ comment("self for call");
		call.self->compile(*this);
		__ mov(rax, GET_TEMPORARY(self_tmp));

		// evaluate arguments and store temporaries
		auto num_args = call.arguments->length();
		uint64_t args_tmp[num_args];
		size_t i = 0;
		for each (arg_iter, call.arguments->nodes) {
			args_tmp[i] = reserve_temporary();
			__ comment(string_printf("argument %d", i));
			(*arg_iter)->compile(*this);
			__ mov(rax, GET_TEMPORARY(args_tmp[i]));
			++i;
		}

		auto function_tmp = self_tmp;
		if (call.member) {
			__ comment("method call");
			function_tmp = reserve_temporary();
			__ mov(GET_TEMPORARY(self_tmp), rdi);
			__ mov(call.member->name.c_str(), rsi);
			__ call("snow_get");
			__ mov(rax, GET_TEMPORARY(function_tmp));
			__ mov(GET_TEMPORARY(self_tmp), rdi);
		} else {
			__ comment("closure call");
			__ clear(rdi);         // "self" is NULL for closures
		}

		__ mov(GET_TEMPORARY(function_tmp), rsi);
		__ mov(num_args, rdx);

		for (size_t i = 0; i < num_args; ++i) {
			const size_t arg_offset = i + 3;

			if (arg_offset < num_arg_regs) {
				__ mov(GET_TEMPORARY(args_tmp[i]), *arg_regs[arg_offset]);
			} else {
				const size_t stack_offset = arg_offset - num_arg_regs;
				if (m_NumStackArguments < stack_offset)
					m_NumStackArguments = stack_offset;
				__ mov(GET_TEMPORARY(args_tmp[i]), rax);
				// XXX: Can this be done without SIB?
				__ mov(stack_offset, rbx);
				__ mov(rax, SIB(rsp, rbx, SIB::SCALE_8));
			}

			free_temporary(args_tmp[i]);
		}

		if (self_tmp == function_tmp)
			free_temporary(self_tmp);
		else {
			free_temporary(self_tmp);
			free_temporary(function_tmp);
		}

		// finally!
		__ clear(rax);
		__ call("snow_call");
	}

	void Codegen::compile(ast::Get& get) {
		__ comment("get `" + get.member->name + "'");
		get.self->compile(*this);
		__ mov(rax, rdi);
		__ mov(get.member->name.c_str(), rsi);
		__ call("snow_get");
	}

	void Codegen::compile(ast::Set& set) {
		__ comment("set `" + set.member->name + "'");
		set.expression->compile(*this);
		auto tmp = reserve_temporary();
		__ mov(rax, GET_TEMPORARY(tmp));
		set.self->compile(*this);
		__ mov(rax, rdi);
		__ mov(set.member->name.c_str(), rsi);
		__ mov(GET_TEMPORARY(tmp), rdx);
		__ call("snow_set");
		free_temporary(tmp);
	}

	void Codegen::compile(ast::Loop& loop) {
		RefPtr<Label> test_cond = new Label;
		RefPtr<Label> body = new Label;
		RefPtr<Label> after = new Label;

		__ bind(test_cond);
		__ comment("loop cond");
		loop.expression->compile(*this);
		__ mov(rax, rdi);
		__ call("snow_eval_truth");
		__ cmp(0, rax);
		__ j(CC_EQUAL, after);
		__ bind(body);
		__ comment("loop body");
		loop.while_true->compile(*this);
		__ jmp(test_cond);
		__ bind(after);
	}

	void Codegen::compile(ast::Self&) {
		__ mov(GET_STACK(self), rax);
	}

	void Codegen::compile(ast::It&) {
		__ mov(GET_STACK(it), rax);
	}
}
}
<|endoftext|>


<commit_before>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2014 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include "xenia/gpu/texture_info.h"

#include <algorithm>
#include <cmath>
#include <cstring>

#include "third_party/xxhash/xxhash.h"
#include "xenia/base/math.h"

namespace xe {
namespace gpu {

using namespace xe::gpu::xenos;

bool TextureInfo::Prepare(const xe_gpu_texture_fetch_t& fetch,
                          TextureInfo* out_info) {
  std::memset(out_info, 0, sizeof(TextureInfo));

  // http://msdn.microsoft.com/en-us/library/windows/desktop/cc308051(v=vs.85).aspx
  // a2xx_sq_surfaceformat
  auto& info = *out_info;
  info.guest_address = fetch.address << 12;

  info.dimension = static_cast<Dimension>(fetch.dimension);
  info.width = info.height = info.depth = 0;
  switch (info.dimension) {
    case Dimension::k1D:
      info.dimension = Dimension::k2D;
      info.width = fetch.size_1d.width;
      info.height = 1;
      break;
    case Dimension::k2D:
      info.width = fetch.size_2d.width;
      info.height = fetch.size_2d.height;
      break;
    case Dimension::k3D:
      info.width = fetch.size_3d.width;
      info.height = fetch.size_3d.height;
      info.depth = fetch.size_3d.depth;
      break;
    case Dimension::kCube:
      info.width = fetch.size_stack.width;
      info.height = fetch.size_stack.height;
      info.depth = fetch.size_stack.depth;
      break;
  }
  info.texture_format = static_cast<TextureFormat>(fetch.format);
  info.endianness = static_cast<Endian>(fetch.endianness);
  info.is_tiled = fetch.tiled;
  info.has_packed_mips = fetch.packed_mips;
  info.input_length = 0;  // Populated below.

  if (info.format_info()->format == TextureFormat::kUnknown) {
    assert_true("Unsupported texture format");
    return false;
  }

  // Must be called here when we know the format.
  switch (info.dimension) {
    case Dimension::k1D: {
      assert_always();
    } break;
    case Dimension::k2D: {
      info.CalculateTextureSizes2D(fetch.size_2d.width + 1,
                                   fetch.size_2d.height + 1);
    } break;
    case Dimension::k3D: {
      // TODO(benvanik): calculate size.
      return false;
    }
    case Dimension::kCube: {
      info.CalculateTextureSizesCube(fetch.size_stack.width + 1,
                                     fetch.size_stack.height + 1,
                                     fetch.size_stack.depth + 1);
    } break;
  }

  return true;
}

bool TextureInfo::PrepareResolve(uint32_t physical_address,
                                 TextureFormat texture_format, Endian endian,
                                 uint32_t width, uint32_t height,
                                 TextureInfo* out_info) {
  std::memset(out_info, 0, sizeof(TextureInfo));
  auto& info = *out_info;
  info.guest_address = physical_address;
  info.dimension = Dimension::k2D;
  assert_true(width > 0);
  assert_true(height > 0);
  info.width = width - 1;
  info.height = height - 1;
  info.texture_format = texture_format;
  info.endianness = endian;
  info.is_tiled = true;
  info.has_packed_mips = false;
  info.input_length = 0;

  if (info.format_info()->format == TextureFormat::kUnknown) {
    assert_true("Unsupported texture format");
    return false;
  }

  info.CalculateTextureSizes2D(width, height);
  return true;
}

void TextureInfo::CalculateTextureSizes2D(uint32_t width, uint32_t height) {
  size_2d.logical_width = width;
  size_2d.logical_height = height;

  // Here be dragons. The values here are used in texture_cache.cc to copy
  // images and create GL textures. Changes here will impact that code.
  // TODO(benvanik): generic texture copying utility.

  auto format = format_info();

  // w/h in blocks.
  uint32_t block_width =
      xe::round_up(size_2d.logical_width, format->block_width) /
      format->block_width;
  uint32_t block_height =
      xe::round_up(size_2d.logical_height, format->block_height) /
      format->block_height;

  // Tiles are 32x32 blocks. The pitch of all textures must a multiple of tile
  // dimensions.
  uint32_t tile_width = xe::round_up(block_width, 32) / 32;
  size_2d.block_width = tile_width * 32;
  size_2d.block_height = block_height;

  uint32_t bytes_per_block =
      format->block_width * format->block_height * format->bits_per_pixel / 8;
  uint32_t byte_pitch = size_2d.block_width * bytes_per_block;

  uint32_t texel_width;
  if (!is_tiled) {
    // Each row must be a multiple of 256 in linear textures.
    byte_pitch = xe::round_up(byte_pitch, 256);
    texel_width = (byte_pitch / bytes_per_block) * format->block_width;
  } else {
    texel_width = size_2d.block_width * format->block_width;
  }

  size_2d.input_width = texel_width;
  size_2d.input_height = size_2d.block_height * format->block_height;
  size_2d.input_pitch = byte_pitch;

  input_length = size_2d.input_pitch * size_2d.block_height;
}

void TextureInfo::CalculateTextureSizesCube(uint32_t width, uint32_t height,
                                            uint32_t depth) {
  assert_true(depth == 6);
  size_cube.logical_width = width;
  size_cube.logical_height = height;

  auto format = format_info();

  // w/h in blocks must be a multiple of block size.
  uint32_t block_width =
      xe::round_up(size_cube.logical_width, format->block_width) /
      format->block_width;
  uint32_t block_height =
      xe::round_up(size_cube.logical_height, format->block_height) /
      format->block_height;

  // Tiles are 32x32 blocks. All textures must be multiples of tile dimensions.
  uint32_t tile_width = xe::round_up(block_width, 32) / 32;
  uint32_t tile_height = xe::round_up(block_height, 32) / 32;
  size_cube.block_width = tile_width * 32;
  size_cube.block_height = tile_height * 32;

  uint32_t bytes_per_block =
      format->block_width * format->block_height * format->bits_per_pixel / 8;
  uint32_t byte_pitch = size_cube.block_width * bytes_per_block;

  uint32_t texel_width;
  if (!is_tiled) {
    // Each row must be a multiple of 256 in linear textures.
    byte_pitch = xe::round_up(byte_pitch, 256);
    texel_width = (byte_pitch / bytes_per_block) * format->block_width;
  } else {
    texel_width = size_cube.block_width * format->block_width;
  }

  size_cube.input_width = texel_width;
  size_cube.input_height = size_cube.block_height * format->block_height;
  size_cube.input_pitch = byte_pitch;

  size_cube.input_face_length = size_cube.input_pitch * size_cube.block_height;
  input_length = size_cube.input_face_length * 6;
}

bool TextureInfo::GetPackedTileOffset(const TextureInfo& texture_info,
                                      uint32_t* out_offset_x,
                                      uint32_t* out_offset_y) {
  // Tile size is 32x32, and once textures go <=16 they are packed into a
  // single tile together. The math here is insane. Most sourced
  // from graph paper and looking at dds dumps.
  //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  // 0         +.4x4.+ +.....8x8.....+ +............16x16............+
  // 1         +.4x4.+ +.....8x8.....+ +............16x16............+
  // 2         +.4x4.+ +.....8x8.....+ +............16x16............+
  // 3         +.4x4.+ +.....8x8.....+ +............16x16............+
  // 4 x               +.....8x8.....+ +............16x16............+
  // 5                 +.....8x8.....+ +............16x16............+
  // 6                 +.....8x8.....+ +............16x16............+
  // 7                 +.....8x8.....+ +............16x16............+
  // 8 2x2                             +............16x16............+
  // 9 2x2                             +............16x16............+
  // 0                                 +............16x16............+
  // ...                                            .....
  // This only works for square textures, or textures that are some non-pot
  // <= square. As soon as the aspect ratio goes weird, the textures start to
  // stretch across tiles.
  // if (tile_aligned(w) > tile_aligned(h)) {
  //   // wider than tall, so packed horizontally
  // } else if (tile_aligned(w) < tile_aligned(h)) {
  //   // taller than wide, so packed vertically
  // } else {
  //   square
  // }
  // It's important to use logical sizes here, as the input sizes will be
  // for the entire packed tile set, not the actual texture.
  // The minimum dimension is what matters most: if either width or height
  // is <= 16 this mode kicks in.

  if (std::min(texture_info.size_2d.logical_width,
               texture_info.size_2d.logical_height) > 16) {
    // Too big, not packed.
    *out_offset_x = 0;
    *out_offset_y = 0;
    return false;
  }

  if (xe::log2_ceil(texture_info.size_2d.logical_width) >
      xe::log2_ceil(texture_info.size_2d.logical_height)) {
    // Wider than tall. Laid out vertically.
    *out_offset_x = 0;
    *out_offset_y = 16;
  } else {
    // Taller than wide. Laid out horizontally.
    *out_offset_x = 16;
    *out_offset_y = 0;
  }
  *out_offset_x /= texture_info.format_info()->block_width;
  *out_offset_y /= texture_info.format_info()->block_height;
  return true;
}

// https://github.com/BinomialLLC/crunch/blob/ea9b8d8c00c8329791256adafa8cf11e4e7942a2/inc/crn_decomp.h#L4108
uint32_t TextureInfo::TiledOffset2DOuter(uint32_t y, uint32_t width,
                                         uint32_t log_bpp) {
  uint32_t macro = ((y >> 5) * (width >> 5)) << (log_bpp + 7);
  uint32_t micro = ((y & 6) << 2) << log_bpp;
  return macro + ((micro & ~15) << 1) + (micro & 15) +
         ((y & 8) << (3 + log_bpp)) + ((y & 1) << 4);
}

uint32_t TextureInfo::TiledOffset2DInner(uint32_t x, uint32_t y, uint32_t bpp,
                                         uint32_t base_offset) {
  uint32_t macro = (x >> 5) << (bpp + 7);
  uint32_t micro = (x & 7) << bpp;
  uint32_t offset = base_offset + (macro + ((micro & ~15) << 1) + (micro & 15));
  return ((offset & ~511) << 3) + ((offset & 448) << 2) + (offset & 63) +
         ((y & 16) << 7) + (((((y & 8) >> 2) + (x >> 3)) & 3) << 6);
}

uint64_t TextureInfo::hash() const {
  return XXH64(this, sizeof(TextureInfo), 0);
}

}  //  namespace gpu
}  //  namespace xe
<commit_msg>[GPU] Log attempts to fetch unsupported texture formats<commit_after>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2014 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include "xenia/gpu/texture_info.h"

#include <algorithm>
#include <cmath>
#include <cstring>

#include "xenia/base/logging.h"
#include "xenia/base/math.h"

#include "third_party/xxhash/xxhash.h"

namespace xe {
namespace gpu {

using namespace xe::gpu::xenos;

bool TextureInfo::Prepare(const xe_gpu_texture_fetch_t& fetch,
                          TextureInfo* out_info) {
  std::memset(out_info, 0, sizeof(TextureInfo));

  // http://msdn.microsoft.com/en-us/library/windows/desktop/cc308051(v=vs.85).aspx
  // a2xx_sq_surfaceformat
  auto& info = *out_info;
  info.guest_address = fetch.address << 12;

  info.dimension = static_cast<Dimension>(fetch.dimension);
  info.width = info.height = info.depth = 0;
  switch (info.dimension) {
    case Dimension::k1D:
      info.dimension = Dimension::k2D;
      info.width = fetch.size_1d.width;
      info.height = 1;
      break;
    case Dimension::k2D:
      info.width = fetch.size_2d.width;
      info.height = fetch.size_2d.height;
      break;
    case Dimension::k3D:
      info.width = fetch.size_3d.width;
      info.height = fetch.size_3d.height;
      info.depth = fetch.size_3d.depth;
      break;
    case Dimension::kCube:
      info.width = fetch.size_stack.width;
      info.height = fetch.size_stack.height;
      info.depth = fetch.size_stack.depth;
      break;
  }
  info.texture_format = static_cast<TextureFormat>(fetch.format);
  info.endianness = static_cast<Endian>(fetch.endianness);
  info.is_tiled = fetch.tiled;
  info.has_packed_mips = fetch.packed_mips;
  info.input_length = 0;  // Populated below.

  if (info.format_info()->format == TextureFormat::kUnknown) {
    XELOGE("Attempting to fetch from unsupported texture format %d",
           info.texture_format);
    return false;
  }

  // Must be called here when we know the format.
  switch (info.dimension) {
    case Dimension::k1D: {
      assert_always();
    } break;
    case Dimension::k2D: {
      info.CalculateTextureSizes2D(fetch.size_2d.width + 1,
                                   fetch.size_2d.height + 1);
    } break;
    case Dimension::k3D: {
      // TODO(benvanik): calculate size.
      return false;
    }
    case Dimension::kCube: {
      info.CalculateTextureSizesCube(fetch.size_stack.width + 1,
                                     fetch.size_stack.height + 1,
                                     fetch.size_stack.depth + 1);
    } break;
  }

  return true;
}

bool TextureInfo::PrepareResolve(uint32_t physical_address,
                                 TextureFormat texture_format, Endian endian,
                                 uint32_t width, uint32_t height,
                                 TextureInfo* out_info) {
  std::memset(out_info, 0, sizeof(TextureInfo));
  auto& info = *out_info;
  info.guest_address = physical_address;
  info.dimension = Dimension::k2D;
  assert_true(width > 0);
  assert_true(height > 0);
  info.width = width - 1;
  info.height = height - 1;
  info.texture_format = texture_format;
  info.endianness = endian;
  info.is_tiled = true;
  info.has_packed_mips = false;
  info.input_length = 0;

  if (info.format_info()->format == TextureFormat::kUnknown) {
    assert_true("Unsupported texture format");
    return false;
  }

  info.CalculateTextureSizes2D(width, height);
  return true;
}

void TextureInfo::CalculateTextureSizes2D(uint32_t width, uint32_t height) {
  size_2d.logical_width = width;
  size_2d.logical_height = height;

  // Here be dragons. The values here are used in texture_cache.cc to copy
  // images and create GL textures. Changes here will impact that code.
  // TODO(benvanik): generic texture copying utility.

  auto format = format_info();

  // w/h in blocks.
  uint32_t block_width =
      xe::round_up(size_2d.logical_width, format->block_width) /
      format->block_width;
  uint32_t block_height =
      xe::round_up(size_2d.logical_height, format->block_height) /
      format->block_height;

  // Tiles are 32x32 blocks. The pitch of all textures must a multiple of tile
  // dimensions.
  uint32_t tile_width = xe::round_up(block_width, 32) / 32;
  size_2d.block_width = tile_width * 32;
  size_2d.block_height = block_height;

  uint32_t bytes_per_block =
      format->block_width * format->block_height * format->bits_per_pixel / 8;
  uint32_t byte_pitch = size_2d.block_width * bytes_per_block;

  uint32_t texel_width;
  if (!is_tiled) {
    // Each row must be a multiple of 256 in linear textures.
    byte_pitch = xe::round_up(byte_pitch, 256);
    texel_width = (byte_pitch / bytes_per_block) * format->block_width;
  } else {
    texel_width = size_2d.block_width * format->block_width;
  }

  size_2d.input_width = texel_width;
  size_2d.input_height = size_2d.block_height * format->block_height;
  size_2d.input_pitch = byte_pitch;

  input_length = size_2d.input_pitch * size_2d.block_height;
}

void TextureInfo::CalculateTextureSizesCube(uint32_t width, uint32_t height,
                                            uint32_t depth) {
  assert_true(depth == 6);
  size_cube.logical_width = width;
  size_cube.logical_height = height;

  auto format = format_info();

  // w/h in blocks must be a multiple of block size.
  uint32_t block_width =
      xe::round_up(size_cube.logical_width, format->block_width) /
      format->block_width;
  uint32_t block_height =
      xe::round_up(size_cube.logical_height, format->block_height) /
      format->block_height;

  // Tiles are 32x32 blocks. All textures must be multiples of tile dimensions.
  uint32_t tile_width = xe::round_up(block_width, 32) / 32;
  uint32_t tile_height = xe::round_up(block_height, 32) / 32;
  size_cube.block_width = tile_width * 32;
  size_cube.block_height = tile_height * 32;

  uint32_t bytes_per_block =
      format->block_width * format->block_height * format->bits_per_pixel / 8;
  uint32_t byte_pitch = size_cube.block_width * bytes_per_block;

  uint32_t texel_width;
  if (!is_tiled) {
    // Each row must be a multiple of 256 in linear textures.
    byte_pitch = xe::round_up(byte_pitch, 256);
    texel_width = (byte_pitch / bytes_per_block) * format->block_width;
  } else {
    texel_width = size_cube.block_width * format->block_width;
  }

  size_cube.input_width = texel_width;
  size_cube.input_height = size_cube.block_height * format->block_height;
  size_cube.input_pitch = byte_pitch;

  size_cube.input_face_length = size_cube.input_pitch * size_cube.block_height;
  input_length = size_cube.input_face_length * 6;
}

bool TextureInfo::GetPackedTileOffset(const TextureInfo& texture_info,
                                      uint32_t* out_offset_x,
                                      uint32_t* out_offset_y) {
  // Tile size is 32x32, and once textures go <=16 they are packed into a
  // single tile together. The math here is insane. Most sourced
  // from graph paper and looking at dds dumps.
  //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  // 0         +.4x4.+ +.....8x8.....+ +............16x16............+
  // 1         +.4x4.+ +.....8x8.....+ +............16x16............+
  // 2         +.4x4.+ +.....8x8.....+ +............16x16............+
  // 3         +.4x4.+ +.....8x8.....+ +............16x16............+
  // 4 x               +.....8x8.....+ +............16x16............+
  // 5                 +.....8x8.....+ +............16x16............+
  // 6                 +.....8x8.....+ +............16x16............+
  // 7                 +.....8x8.....+ +............16x16............+
  // 8 2x2                             +............16x16............+
  // 9 2x2                             +............16x16............+
  // 0                                 +............16x16............+
  // ...                                            .....
  // This only works for square textures, or textures that are some non-pot
  // <= square. As soon as the aspect ratio goes weird, the textures start to
  // stretch across tiles.
  // if (tile_aligned(w) > tile_aligned(h)) {
  //   // wider than tall, so packed horizontally
  // } else if (tile_aligned(w) < tile_aligned(h)) {
  //   // taller than wide, so packed vertically
  // } else {
  //   square
  // }
  // It's important to use logical sizes here, as the input sizes will be
  // for the entire packed tile set, not the actual texture.
  // The minimum dimension is what matters most: if either width or height
  // is <= 16 this mode kicks in.

  if (std::min(texture_info.size_2d.logical_width,
               texture_info.size_2d.logical_height) > 16) {
    // Too big, not packed.
    *out_offset_x = 0;
    *out_offset_y = 0;
    return false;
  }

  if (xe::log2_ceil(texture_info.size_2d.logical_width) >
      xe::log2_ceil(texture_info.size_2d.logical_height)) {
    // Wider than tall. Laid out vertically.
    *out_offset_x = 0;
    *out_offset_y = 16;
  } else {
    // Taller than wide. Laid out horizontally.
    *out_offset_x = 16;
    *out_offset_y = 0;
  }
  *out_offset_x /= texture_info.format_info()->block_width;
  *out_offset_y /= texture_info.format_info()->block_height;
  return true;
}

// https://github.com/BinomialLLC/crunch/blob/ea9b8d8c00c8329791256adafa8cf11e4e7942a2/inc/crn_decomp.h#L4108
uint32_t TextureInfo::TiledOffset2DOuter(uint32_t y, uint32_t width,
                                         uint32_t log_bpp) {
  uint32_t macro = ((y >> 5) * (width >> 5)) << (log_bpp + 7);
  uint32_t micro = ((y & 6) << 2) << log_bpp;
  return macro + ((micro & ~15) << 1) + (micro & 15) +
         ((y & 8) << (3 + log_bpp)) + ((y & 1) << 4);
}

uint32_t TextureInfo::TiledOffset2DInner(uint32_t x, uint32_t y, uint32_t bpp,
                                         uint32_t base_offset) {
  uint32_t macro = (x >> 5) << (bpp + 7);
  uint32_t micro = (x & 7) << bpp;
  uint32_t offset = base_offset + (macro + ((micro & ~15) << 1) + (micro & 15));
  return ((offset & ~511) << 3) + ((offset & 448) << 2) + (offset & 63) +
         ((y & 16) << 7) + (((((y & 8) >> 2) + (x >> 3)) & 3) << 6);
}

uint64_t TextureInfo::hash() const {
  return XXH64(this, sizeof(TextureInfo), 0);
}

}  //  namespace gpu
}  //  namespace xe
<|endoftext|>


<commit_before>//===- unittests/StaticAnalyzer/SymbolReaperTest.cpp ----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/CrossTU/CrossTranslationUnit.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
#include "clang/Tooling/Tooling.h"
#include "gtest/gtest.h"

namespace clang {
namespace ento {
namespace {

using namespace ast_matchers;

// A re-usable consumer that constructs ExprEngine out of CompilerInvocation.
// TODO: Actually re-use it when we write our second test.
class ExprEngineConsumer : public ASTConsumer {
protected:
  CompilerInstance &C;

private:
  // We need to construct all of these in order to construct ExprEngine.
  CheckerManager ChkMgr;
  cross_tu::CrossTranslationUnitContext CTU;
  PathDiagnosticConsumers Consumers;
  AnalysisManager AMgr;
  SetOfConstDecls VisitedCallees;
  FunctionSummariesTy FS;

protected:
  ExprEngine Eng;

  // Find a declaration in the current AST by name. This has nothing to do
  // with ExprEngine but turns out to be handy.
  // TODO: There's probably a better place for it.
  template <typename T>
  const T *findDeclByName(const Decl *Where, StringRef Name) {
    auto Matcher = decl(hasDescendant(namedDecl(hasName(Name)).bind("d")));
    auto Matches = match(Matcher, *Where, Eng.getContext());
    assert(Matches.size() == 1 && "Ambiguous name!");
    const T *Node = selectFirst<T>("d", Matches);
    assert(Node && "Name not found!");
    return Node;
  }

public:
  ExprEngineConsumer(CompilerInstance &C)
      : C(C), ChkMgr(C.getASTContext(), *C.getAnalyzerOpts()), CTU(C),
        Consumers(),
        AMgr(C.getASTContext(), C.getDiagnostics(), Consumers,
             CreateRegionStoreManager, CreateRangeConstraintManager, &ChkMgr,
             *C.getAnalyzerOpts()),
        VisitedCallees(), FS(),
        Eng(CTU, AMgr, &VisitedCallees, &FS, ExprEngine::Inline_Regular) {}
};

class SuperRegionLivenessConsumer : public ExprEngineConsumer {
  void performTest(const Decl *D) {
    const auto *FD = findDeclByName<FieldDecl>(D, "x");
    const auto *VD = findDeclByName<VarDecl>(D, "s");
    assert(FD && VD);

    // The variable must belong to a stack frame,
    // otherwise SymbolReaper would think it's a global.
    const StackFrameContext *SFC =
        Eng.getAnalysisDeclContextManager().getStackFrame(D);

    // Create regions for 's' and 's.x'.
    const VarRegion *VR = Eng.getRegionManager().getVarRegion(VD, SFC);
    const FieldRegion *FR = Eng.getRegionManager().getFieldRegion(FD, VR);

    // Pass a null location context to the SymbolReaper so that
    // it was thinking that the variable is dead.
    SymbolReaper SymReaper((StackFrameContext *)nullptr, (Stmt *)nullptr,
                           Eng.getSymbolManager(), Eng.getStoreManager());

    SymReaper.markLive(FR);
    EXPECT_TRUE(SymReaper.isLiveRegion(VR));
  }

public:
  SuperRegionLivenessConsumer(CompilerInstance &C) : ExprEngineConsumer(C) {}
  ~SuperRegionLivenessConsumer() override {}

  bool HandleTopLevelDecl(DeclGroupRef DG) override {
    for (const auto *D : DG)
      performTest(D);
    return true;
  }
};

class SuperRegionLivenessAction: public ASTFrontendAction {
public:
  SuperRegionLivenessAction() {}
  std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
                                                 StringRef File) override {
    auto Consumer = llvm::make_unique<SuperRegionLivenessConsumer>(Compiler);
    return Consumer;
  }
};

// Test that marking s.x as live would also make s live.
TEST(SymbolReaper, SuperRegionLiveness) {
  EXPECT_TRUE(tooling::runToolOnCode(new SuperRegionLivenessAction,
                                     "void foo() { struct S { int x; } s; }"));
}

} // namespace
} // namespace ento
} // namespace clang
<commit_msg>[analyzer] A speculative fix for buildbot failures in the new SymbolReaperTest.<commit_after>//===- unittests/StaticAnalyzer/SymbolReaperTest.cpp ----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/CrossTU/CrossTranslationUnit.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
#include "clang/Tooling/Tooling.h"
#include "gtest/gtest.h"

namespace clang {
namespace ento {
namespace {

using namespace ast_matchers;

// A re-usable consumer that constructs ExprEngine out of CompilerInvocation.
// TODO: Actually re-use it when we write our second test.
class ExprEngineConsumer : public ASTConsumer {
protected:
  CompilerInstance &C;

private:
  // We need to construct all of these in order to construct ExprEngine.
  CheckerManager ChkMgr;
  cross_tu::CrossTranslationUnitContext CTU;
  PathDiagnosticConsumers Consumers;
  AnalysisManager AMgr;
  SetOfConstDecls VisitedCallees;
  FunctionSummariesTy FS;

protected:
  ExprEngine Eng;

  // Find a declaration in the current AST by name. This has nothing to do
  // with ExprEngine but turns out to be handy.
  // TODO: There's probably a better place for it.
  template <typename T>
  const T *findDeclByName(const Decl *Where, StringRef Name) {
    auto Matcher = decl(hasDescendant(namedDecl(hasName(Name)).bind("d")));
    auto Matches = match(Matcher, *Where, Eng.getContext());
    assert(Matches.size() == 1 && "Ambiguous name!");
    const T *Node = selectFirst<T>("d", Matches);
    assert(Node && "Name not found!");
    return Node;
  }

public:
  ExprEngineConsumer(CompilerInstance &C)
      : C(C), ChkMgr(C.getASTContext(), *C.getAnalyzerOpts()), CTU(C),
        Consumers(),
        AMgr(C.getASTContext(), C.getDiagnostics(), Consumers,
             CreateRegionStoreManager, CreateRangeConstraintManager, &ChkMgr,
             *C.getAnalyzerOpts()),
        VisitedCallees(), FS(),
        Eng(CTU, AMgr, &VisitedCallees, &FS, ExprEngine::Inline_Regular) {}
};

class SuperRegionLivenessConsumer : public ExprEngineConsumer {
  void performTest(const Decl *D) {
    const auto *FD = findDeclByName<FieldDecl>(D, "x");
    const auto *VD = findDeclByName<VarDecl>(D, "s");
    assert(FD && VD);

    // The variable must belong to a stack frame,
    // otherwise SymbolReaper would think it's a global.
    const StackFrameContext *SFC =
        Eng.getAnalysisDeclContextManager().getStackFrame(D);

    // Create regions for 's' and 's.x'.
    const VarRegion *VR = Eng.getRegionManager().getVarRegion(VD, SFC);
    const FieldRegion *FR = Eng.getRegionManager().getFieldRegion(FD, VR);

    // Pass a null location context to the SymbolReaper so that
    // it was thinking that the variable is dead.
    SymbolReaper SymReaper((StackFrameContext *)nullptr, (Stmt *)nullptr,
                           Eng.getSymbolManager(), Eng.getStoreManager());

    SymReaper.markLive(FR);
    EXPECT_TRUE(SymReaper.isLiveRegion(VR));
  }

public:
  SuperRegionLivenessConsumer(CompilerInstance &C) : ExprEngineConsumer(C) {}
  ~SuperRegionLivenessConsumer() override {}

  bool HandleTopLevelDecl(DeclGroupRef DG) override {
    for (const auto *D : DG)
      performTest(D);
    return true;
  }
};

class SuperRegionLivenessAction: public ASTFrontendAction {
public:
  SuperRegionLivenessAction() {}
  std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
                                                 StringRef File) override {
    return llvm::make_unique<SuperRegionLivenessConsumer>(Compiler);
  }
};

// Test that marking s.x as live would also make s live.
TEST(SymbolReaper, SuperRegionLiveness) {
  EXPECT_TRUE(tooling::runToolOnCode(new SuperRegionLivenessAction,
                                     "void foo() { struct S { int x; } s; }"));
}

} // namespace
} // namespace ento
} // namespace clang
<|endoftext|>


<commit_before>#include<iostream>
#include<SDL2/SDL.h>

SDL_Window *window = nullptr;
SDL_Renderer *renderer = nullptr;

int main(int argc, char **args)
{
    if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
        std::cout << "SDL_Init Error: " << SDL_GetError() << std::endl;
        return 1;
    }

    const char windowTitle[] = "Chapter 1: Setting up SDL";
    window = SDL_CreateWindow(windowTitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_SHOWN);

    if (window == nullptr) {
        std::cout << "SDL_CreateWindow Error: " << SDL_GetError() << std::endl;
        return 1;
    }

    renderer = SDL_CreateRenderer(window, -1, 0);

    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);

    SDL_RenderClear(renderer);

    SDL_RenderPresent(renderer);

    SDL_Delay(5000);

    SDL_Quit();

    return 0;
}
<commit_msg>Modified std::cout to std::cerr in error messages.<commit_after>#include<iostream>
#include<SDL2/SDL.h>

SDL_Window *window = nullptr;
SDL_Renderer *renderer = nullptr;

int main(int argc, char **args)
{
    if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
        std::cerr << "SDL_Init Error: " << SDL_GetError() << std::endl;
        return 1;
    }

    const char windowTitle[] = "Chapter 1: Setting up SDL";
    window = SDL_CreateWindow(windowTitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_SHOWN);

    if (window == nullptr) {
        std::cerr << "SDL_CreateWindow Error: " << SDL_GetError() << std::endl;
        return 1;
    }

    renderer = SDL_CreateRenderer(window, -1, 0);

    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);

    SDL_RenderClear(renderer);

    SDL_RenderPresent(renderer);

    SDL_Delay(5000);

    SDL_Quit();

    return 0;
}
<|endoftext|>


<commit_before>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2019-2021 Baldur Karlsson
 *
 * 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.
 ******************************************************************************/

#include "d3d12_test.h"

RD_TEST(D3D12_Parameter_Zoo, D3D12GraphicsTest)
{
  static constexpr const char *Description =
      "General tests of parameters known to cause problems - e.g. optional values that should be "
      "ignored, edge cases, special values, etc.";

  std::string pixel = R"EOSHADER(

Texture2D<float> empty : register(t50);

float4 main() : SV_Target0
{
	return float4(0, 1, 0, 1) + empty.Load(int3(0,0,0));
}

)EOSHADER";

  int main()
  {
    // initialise, create window, create device, etc
    if(!Init())
      return 3;

    ID3DBlobPtr vsblob = Compile(D3DDefaultVertex, "main", "vs_4_0");
    ID3DBlobPtr psblob = Compile(pixel, "main", "ps_4_0");

    uint32_t indices[1024 / 4] = {0, 1, 2};

    ID3D12ResourcePtr vb = MakeBuffer().Data(DefaultTri);
    ID3D12ResourcePtr ib = MakeBuffer().Data(indices);

    ID3D12RootSignaturePtr sig = MakeSig({
        // table that's larger than the descriptor heap we'll bind
        tableParam(D3D12_SHADER_VISIBILITY_PIXEL, D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, 50, 999, 0),
    });

    ResourceBarrier(vb, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);

    D3D12PSOCreator psoCreator = MakePSO().RootSig(sig).InputLayout().VS(vsblob).PS(psblob);
    psoCreator.GraphicsDesc.StreamOutput.NumEntries = 0;
    psoCreator.GraphicsDesc.StreamOutput.pSODeclaration = (D3D12_SO_DECLARATION_ENTRY *)0x3456;
    psoCreator.GraphicsDesc.StreamOutput.NumStrides = 0xcccccccc;
    psoCreator.GraphicsDesc.StreamOutput.pBufferStrides = (UINT *)0x1234;

    ID3D12RootSignaturePtr duplicateSig = MakeSig(
        {
            cbvParam(D3D12_SHADER_VISIBILITY_PIXEL, 0, 0),
            constParam(D3D12_SHADER_VISIBILITY_PIXEL, 0, 1, 1),
        },
        D3D12_ROOT_SIGNATURE_FLAG_NONE);

    ID3D12DescriptorHeapPtr descHeap;

    {
      D3D12_DESCRIPTOR_HEAP_DESC desc;
      desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
      desc.NodeMask = 1;
      desc.NumDescriptors = 4;
      desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
      CHECK_HR(dev->CreateDescriptorHeap(&desc, __uuidof(ID3D12DescriptorHeap), (void **)&descHeap));
    }

    D3D12_GPU_DESCRIPTOR_HANDLE descGPUHandle = descHeap->GetGPUDescriptorHandleForHeapStart();

    D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
    srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
    srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
    srvDesc.Texture2D.MipLevels = 1;

    dev->CreateShaderResourceView(NULL, &srvDesc, descHeap->GetCPUDescriptorHandleForHeapStart());

    ID3D12PipelineStatePtr pso = psoCreator;

    // if D3D12.4 (??) is available, use different interfaces
    if(dev4)
    {
      GPUSync();

      D3D12_RESOURCE_DESC desc;
      desc.Alignment = 0;
      desc.DepthOrArraySize = 1;
      desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
      desc.Flags = D3D12_RESOURCE_FLAG_NONE;
      desc.Format = DXGI_FORMAT_UNKNOWN;
      desc.Height = 1;
      desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
      desc.Width = sizeof(DefaultTri);
      desc.MipLevels = 1;
      desc.SampleDesc.Count = 1;
      desc.SampleDesc.Quality = 0;

      D3D12_HEAP_DESC heapDesc;
      heapDesc.SizeInBytes = 4096;
      heapDesc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;
      heapDesc.Alignment = 0;
      heapDesc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT;
      heapDesc.Properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
      heapDesc.Properties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
      heapDesc.Properties.CreationNodeMask = 1;
      heapDesc.Properties.VisibleNodeMask = 1;

      CHECK_HR(dev4->CreateCommittedResource1(&heapDesc.Properties, D3D12_HEAP_FLAG_NONE, &desc,
                                              D3D12_RESOURCE_STATE_COMMON, NULL, NULL,
                                              __uuidof(ID3D12Resource), (void **)&vb));

      SetBufferData(vb, D3D12_RESOURCE_STATE_COMMON, (const byte *)DefaultTri, sizeof(DefaultTri));

      ID3D12Heap1Ptr heap;
      CHECK_HR(dev4->CreateHeap1(&heapDesc, NULL, __uuidof(ID3D12Heap1), (void **)&heap));

      desc.Width = sizeof(indices);

      CHECK_HR(dev4->CreatePlacedResource(heap, 0, &desc, D3D12_RESOURCE_STATE_COMMON, NULL,
                                          __uuidof(ID3D12Resource), (void **)&ib));

      SetBufferData(ib, D3D12_RESOURCE_STATE_COMMON, (const byte *)indices, sizeof(indices));
    }

    ID3D12ResourcePtr rtvtex = MakeTexture(DXGI_FORMAT_R32G32B32A32_FLOAT, 4, 4)
                                   .RTV()
                                   .InitialState(D3D12_RESOURCE_STATE_RENDER_TARGET);

    ID3D12CommandSignaturePtr cmdsig = MakeCommandSig(NULL, {vbArg(0), drawArg()});
    ID3D12ResourcePtr argBuf = MakeBuffer().Upload().Size(1024);

    while(Running())
    {
      ID3D12GraphicsCommandListPtr cmd = GetCommandBuffer();

      Reset(cmd);

      ID3D12DebugCommandListPtr debug = cmd;

      ID3D12ResourcePtr bb = StartUsingBackbuffer(cmd, D3D12_RESOURCE_STATE_RENDER_TARGET);

      // force duplicate signature to be used
      cmd->SetGraphicsRootSignature(duplicateSig);

      if(debug)
        debug->AssertResourceState(bb, D3D12_RESOURCE_STATE_RENDER_TARGET, 0);

      D3D12_CPU_DESCRIPTOR_HANDLE rtv =
          MakeRTV(bb).Format(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB).CreateCPU(0);

      ClearRenderTargetView(cmd, rtv, {1.0f, 0.0f, 1.0f, 1.0f});

      cmd->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

      cmd->SetDescriptorHeaps(1, &descHeap.GetInterfacePtr());

      IASetVertexBuffer(cmd, vb, sizeof(DefaultA2V), 0);
      D3D12_INDEX_BUFFER_VIEW view;
      view.BufferLocation = ib->GetGPUVirtualAddress();
      view.Format = DXGI_FORMAT_R32_UINT;
      view.SizeInBytes = 1024;
      cmd->IASetIndexBuffer(&view);
      cmd->SetPipelineState(pso);
      cmd->SetGraphicsRootSignature(sig);
      cmd->SetGraphicsRootDescriptorTable(0, descGPUHandle);

      RSSetViewport(cmd, {0.0f, 0.0f, (float)screenWidth, (float)screenHeight, 0.0f, 1.0f});
      RSSetScissorRect(cmd, {0, 0, screenWidth, screenHeight});

      // trash slots 3 and 4
      D3D12_CPU_DESCRIPTOR_HANDLE rtv3 = MakeRTV(rtvtex).CreateCPU(3);
      D3D12_CPU_DESCRIPTOR_HANDLE rtv4 = MakeRTV(rtvtex).CreateCPU(4);

      // write the proper RTV to slot 3
      MakeRTV(bb).Format(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB).CreateCPU(3);

      // copy to slot 4
      dev->CopyDescriptorsSimple(1, rtv4, rtv3, D3D12_DESCRIPTOR_HEAP_TYPE_RTV);

      // bind from slot 4
      cmd->OMSetRenderTargets(1, &rtv4, FALSE, NULL);

      // trash RTV slots 3 and 4 again
      MakeRTV(rtvtex).CreateCPU(3);
      MakeRTV(rtvtex).CreateCPU(4);

      setMarker(cmd, "Color Draw");

      cmd->DrawIndexedInstanced(3, 1, 0, 0, 0);

      setMarker(cmd, "Empty indirect execute");

      cmd->ExecuteIndirect(cmdsig, 0, argBuf, 0, NULL, 0);

      FinishUsingBackbuffer(cmd, D3D12_RESOURCE_STATE_RENDER_TARGET);

      if(debug)
      {
        BOOL wrong = debug->AssertResourceState(bb, D3D12_RESOURCE_STATE_COPY_DEST, 0);
        BOOL right = debug->AssertResourceState(bb, D3D12_RESOURCE_STATE_PRESENT, 0);

        if(wrong == TRUE)
          TEST_WARN("Didn't get the expected return value from AssertResourceState(COPY_DEST)");
        if(right == FALSE)
          TEST_WARN("Didn't get the expected return value from AssertResourceState(PRESENT)");
      }

      cmd->Close();

      Submit({cmd});

      Present();
    }

    return 0;
  }
};

REGISTER_TEST();
<commit_msg>Test stream-created PSOs create correctly<commit_after>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2019-2021 Baldur Karlsson
 *
 * 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.
 ******************************************************************************/

#include "d3d12_test.h"

RD_TEST(D3D12_Parameter_Zoo, D3D12GraphicsTest)
{
  static constexpr const char *Description =
      "General tests of parameters known to cause problems - e.g. optional values that should be "
      "ignored, edge cases, special values, etc.";

  std::string pixel = R"EOSHADER(

Texture2D<float> empty : register(t50);

float4 main() : SV_Target0
{
	return float4(0, 1, 0, 1) + empty.Load(int3(0,0,0));
}

)EOSHADER";

  int main()
  {
    // initialise, create window, create device, etc
    if(!Init())
      return 3;

    ID3DBlobPtr vsblob = Compile(D3DDefaultVertex, "main", "vs_4_0");
    ID3DBlobPtr psblob = Compile(pixel, "main", "ps_4_0");

    uint32_t indices[1024 / 4] = {0, 1, 2};

    ID3D12ResourcePtr vb = MakeBuffer().Data(DefaultTri);
    ID3D12ResourcePtr ib = MakeBuffer().Data(indices);

    ID3D12RootSignaturePtr sig = MakeSig({
        // table that's larger than the descriptor heap we'll bind
        tableParam(D3D12_SHADER_VISIBILITY_PIXEL, D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, 50, 999, 0),
    });

    ResourceBarrier(vb, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);

    D3D12PSOCreator psoCreator = MakePSO().RootSig(sig).InputLayout().VS(vsblob).PS(psblob);
    psoCreator.GraphicsDesc.StreamOutput.NumEntries = 0;
    psoCreator.GraphicsDesc.StreamOutput.pSODeclaration = (D3D12_SO_DECLARATION_ENTRY *)0x3456;
    psoCreator.GraphicsDesc.StreamOutput.NumStrides = 0xcccccccc;
    psoCreator.GraphicsDesc.StreamOutput.pBufferStrides = (UINT *)0x1234;

    ID3D12RootSignaturePtr duplicateSig = MakeSig(
        {
            cbvParam(D3D12_SHADER_VISIBILITY_PIXEL, 0, 0),
            constParam(D3D12_SHADER_VISIBILITY_PIXEL, 0, 1, 1),
        },
        D3D12_ROOT_SIGNATURE_FLAG_NONE);

    ID3D12DescriptorHeapPtr descHeap;

    {
      D3D12_DESCRIPTOR_HEAP_DESC desc;
      desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
      desc.NodeMask = 1;
      desc.NumDescriptors = 4;
      desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
      CHECK_HR(dev->CreateDescriptorHeap(&desc, __uuidof(ID3D12DescriptorHeap), (void **)&descHeap));
    }

    D3D12_GPU_DESCRIPTOR_HANDLE descGPUHandle = descHeap->GetGPUDescriptorHandleForHeapStart();

    D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
    srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
    srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
    srvDesc.Texture2D.MipLevels = 1;

    dev->CreateShaderResourceView(NULL, &srvDesc, descHeap->GetCPUDescriptorHandleForHeapStart());

    ID3D12PipelineStatePtr pso = psoCreator;
    ID3D12PipelineStatePtr pso2;

    if(dev2)
    {
      struct StreamStructBase
      {
        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE rootsig_type =
            D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE;
        UINT padding0;
        ID3D12RootSignature *pRootSignature;

        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE vs_type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS;
        UINT padding1;
        D3D12_SHADER_BYTECODE vs = {};
        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE ps_type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS;
        UINT padding2;
        D3D12_SHADER_BYTECODE ps = {};

        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE input_type =
            D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT;
        D3D12_INPUT_LAYOUT_DESC InputLayout;
        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE mask_type =
            D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK;
        UINT SampleMask;
        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE dsv_type =
            D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT;
        DXGI_FORMAT DSVFormat;
        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE blend_type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND;
        D3D12_BLEND_DESC BlendState;
        UINT padding3;
        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE rast_type =
            D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER;
        D3D12_RASTERIZER_DESC RasterizerState;
        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE depth_type =
            D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL;
        D3D12_DEPTH_STENCIL_DESC DepthStencilState;
        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE prim_type =
            D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY;
        D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType;
        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE rtv_type =
            D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS;
        D3D12_RT_FORMAT_ARRAY RTVFormats;
      };

      struct StreamStructMesh : StreamStructBase
      {
        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE as_type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS;
        UINT padding3;
        D3D12_SHADER_BYTECODE as = {};
        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE ms_type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS;
        UINT padding4;
        D3D12_SHADER_BYTECODE ms = {};
      } streamStruct;

      streamStruct.InputLayout = psoCreator.GraphicsDesc.InputLayout;
      streamStruct.pRootSignature = psoCreator.GraphicsDesc.pRootSignature;
      streamStruct.vs = psoCreator.GraphicsDesc.VS;
      streamStruct.ps = psoCreator.GraphicsDesc.PS;
      streamStruct.SampleMask = psoCreator.GraphicsDesc.SampleMask;
      streamStruct.DSVFormat = psoCreator.GraphicsDesc.DSVFormat;
      streamStruct.BlendState = psoCreator.GraphicsDesc.BlendState;
      streamStruct.RasterizerState = psoCreator.GraphicsDesc.RasterizerState;
      streamStruct.DepthStencilState = psoCreator.GraphicsDesc.DepthStencilState;
      streamStruct.PrimitiveTopologyType = psoCreator.GraphicsDesc.PrimitiveTopologyType;
      memcpy(&streamStruct.RTVFormats.RTFormats, &psoCreator.GraphicsDesc.RTVFormats,
             sizeof(D3D12_RT_FORMAT_ARRAY));
      streamStruct.RTVFormats.NumRenderTargets = 1;

      D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {};
      streamDesc.pPipelineStateSubobjectStream = &streamStruct;
      streamDesc.SizeInBytes = sizeof(StreamStructMesh);

      // if the device understands the options7 query we assume it can handle mesh shader structs?
      HRESULT hr = dev2->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, &opts7, sizeof(opts7));
      if(hr != S_OK)
      {
        streamDesc.SizeInBytes = sizeof(StreamStructBase);
      }

      hr = dev2->CreatePipelineState(&streamDesc, __uuidof(ID3D12PipelineState), (void **)&pso2);

      TEST_ASSERT(hr == S_OK, "Pipe created");
    }

    // if D3D12.4 (??) is available, use different interfaces
    if(dev4)
    {
      GPUSync();

      D3D12_RESOURCE_DESC desc;
      desc.Alignment = 0;
      desc.DepthOrArraySize = 1;
      desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
      desc.Flags = D3D12_RESOURCE_FLAG_NONE;
      desc.Format = DXGI_FORMAT_UNKNOWN;
      desc.Height = 1;
      desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
      desc.Width = sizeof(DefaultTri);
      desc.MipLevels = 1;
      desc.SampleDesc.Count = 1;
      desc.SampleDesc.Quality = 0;

      D3D12_HEAP_DESC heapDesc;
      heapDesc.SizeInBytes = 4096;
      heapDesc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;
      heapDesc.Alignment = 0;
      heapDesc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT;
      heapDesc.Properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
      heapDesc.Properties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
      heapDesc.Properties.CreationNodeMask = 1;
      heapDesc.Properties.VisibleNodeMask = 1;

      CHECK_HR(dev4->CreateCommittedResource1(&heapDesc.Properties, D3D12_HEAP_FLAG_NONE, &desc,
                                              D3D12_RESOURCE_STATE_COMMON, NULL, NULL,
                                              __uuidof(ID3D12Resource), (void **)&vb));

      SetBufferData(vb, D3D12_RESOURCE_STATE_COMMON, (const byte *)DefaultTri, sizeof(DefaultTri));

      ID3D12Heap1Ptr heap;
      CHECK_HR(dev4->CreateHeap1(&heapDesc, NULL, __uuidof(ID3D12Heap1), (void **)&heap));

      desc.Width = sizeof(indices);

      CHECK_HR(dev4->CreatePlacedResource(heap, 0, &desc, D3D12_RESOURCE_STATE_COMMON, NULL,
                                          __uuidof(ID3D12Resource), (void **)&ib));

      SetBufferData(ib, D3D12_RESOURCE_STATE_COMMON, (const byte *)indices, sizeof(indices));
    }

    ID3D12ResourcePtr rtvtex = MakeTexture(DXGI_FORMAT_R32G32B32A32_FLOAT, 4, 4)
                                   .RTV()
                                   .InitialState(D3D12_RESOURCE_STATE_RENDER_TARGET);

    ID3D12CommandSignaturePtr cmdsig = MakeCommandSig(NULL, {vbArg(0), drawArg()});
    ID3D12ResourcePtr argBuf = MakeBuffer().Upload().Size(1024);

    while(Running())
    {
      ID3D12GraphicsCommandListPtr cmd = GetCommandBuffer();

      Reset(cmd);

      ID3D12DebugCommandListPtr debug = cmd;

      ID3D12ResourcePtr bb = StartUsingBackbuffer(cmd, D3D12_RESOURCE_STATE_RENDER_TARGET);

      // force duplicate signature to be used
      cmd->SetGraphicsRootSignature(duplicateSig);

      if(debug)
        debug->AssertResourceState(bb, D3D12_RESOURCE_STATE_RENDER_TARGET, 0);

      D3D12_CPU_DESCRIPTOR_HANDLE rtv =
          MakeRTV(bb).Format(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB).CreateCPU(0);

      ClearRenderTargetView(cmd, rtv, {1.0f, 0.0f, 1.0f, 1.0f});

      cmd->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

      cmd->SetDescriptorHeaps(1, &descHeap.GetInterfacePtr());

      IASetVertexBuffer(cmd, vb, sizeof(DefaultA2V), 0);
      D3D12_INDEX_BUFFER_VIEW view;
      view.BufferLocation = ib->GetGPUVirtualAddress();
      view.Format = DXGI_FORMAT_R32_UINT;
      view.SizeInBytes = 1024;
      cmd->IASetIndexBuffer(&view);
      if(pso2)
        cmd->SetPipelineState(pso2);
      cmd->SetPipelineState(pso);
      cmd->SetGraphicsRootSignature(sig);
      cmd->SetGraphicsRootDescriptorTable(0, descGPUHandle);

      RSSetViewport(cmd, {0.0f, 0.0f, (float)screenWidth, (float)screenHeight, 0.0f, 1.0f});
      RSSetScissorRect(cmd, {0, 0, screenWidth, screenHeight});

      // trash slots 3 and 4
      D3D12_CPU_DESCRIPTOR_HANDLE rtv3 = MakeRTV(rtvtex).CreateCPU(3);
      D3D12_CPU_DESCRIPTOR_HANDLE rtv4 = MakeRTV(rtvtex).CreateCPU(4);

      // write the proper RTV to slot 3
      MakeRTV(bb).Format(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB).CreateCPU(3);

      // copy to slot 4
      dev->CopyDescriptorsSimple(1, rtv4, rtv3, D3D12_DESCRIPTOR_HEAP_TYPE_RTV);

      // bind from slot 4
      cmd->OMSetRenderTargets(1, &rtv4, FALSE, NULL);

      // trash RTV slots 3 and 4 again
      MakeRTV(rtvtex).CreateCPU(3);
      MakeRTV(rtvtex).CreateCPU(4);

      setMarker(cmd, "Color Draw");

      cmd->DrawIndexedInstanced(3, 1, 0, 0, 0);

      setMarker(cmd, "Empty indirect execute");

      cmd->ExecuteIndirect(cmdsig, 0, argBuf, 0, NULL, 0);

      FinishUsingBackbuffer(cmd, D3D12_RESOURCE_STATE_RENDER_TARGET);

      if(debug)
      {
        BOOL wrong = debug->AssertResourceState(bb, D3D12_RESOURCE_STATE_COPY_DEST, 0);
        BOOL right = debug->AssertResourceState(bb, D3D12_RESOURCE_STATE_PRESENT, 0);

        if(wrong == TRUE)
          TEST_WARN("Didn't get the expected return value from AssertResourceState(COPY_DEST)");
        if(right == FALSE)
          TEST_WARN("Didn't get the expected return value from AssertResourceState(PRESENT)");
      }

      cmd->Close();

      Submit({cmd});

      Present();
    }

    return 0;
  }
};

REGISTER_TEST();
<|endoftext|>