I am trying to write the simplest possible compute shader in DirectX12 so that I can have a starting point for a real project. However, it seems like no matter what I do I am unable to get my GPU to process "1+1" and see the output. As there is almost no documentation on compute shaders, I figured my only option now is to query StackOverflow.
I wrote the following code using the D3D12nBodyGravity project. First I copied as much of the code over as verbatim as possible, fixed "small" things, and then once it was all working I started trimming the code down to the basics. I am using Visual Studio 2019.
myClass.cpp:
#include "pch.h"
#include "myClass.h"
#include <d3dcompiler.h> // D3DReadFileToBlob
#include "Common\DirectXHelper.h" // NAME_D3D12_OBJECT
#include "Common\Device.h"
#include <iostream>
// InterlockedCompareExchange returns the object's value if the
// comparison fails. If it is already 0, then its value won't
// change and 0 will be returned.
#define InterlockedGetValue(object) InterlockedCompareExchange(object, 0, 0)
myClass::myClass()
: m_frameIndex(0)
, m_UavDescriptorSize(0)
, m_renderContextFenceValue(0)
, m_frameFenceValues{} {
std::cout << "Initializing myClass" << std::endl;
m_FenceValue = 0;
//std::cout << "Calling DXGIDeclareAdapterRemovalSupport()" << std::endl;
//DX::ThrowIfFailed(DXGIDeclareAdapterRemovalSupport());
// Identify the device
std::cout << "Identifying the device" << std::endl;
auto m_device = Device::Get().GetDevice();
std::cout << "Leading the rendering pipeline dependencies" << std::endl;
// Load the rendering pipeline dependencies.
{
std::cout << " Creating the root signatures" << std::endl;
// Create the root signatures.
{
CD3DX12_ROOT_PARAMETER rootParameter;
rootParameter.InitAsUnorderedAccessView(0);
Microsoft::WRL::ComPtr<ID3DBlob> signature;
Microsoft::WRL::ComPtr<ID3DBlob> error;
CD3DX12_ROOT_SIGNATURE_DESC computeRootSignatureDesc(1, &rootParameter, 0, nullptr);
DX::ThrowIfFailed(D3D12SerializeRootSignature(&computeRootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error));
DX::ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_computeRootSignature)));
}
// Describe and create the command queue.
std::cout << " Describing and creating the command queue" << std::endl;
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
DX::ThrowIfFailed(m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_commandQueue)));
NAME_D3D12_OBJECT(m_commandQueue);
std::cout << " Creating descriptor heaps" << std::endl;
// Create descriptor heaps.
{
// Describe and create a shader resource view (SRV) and unordered
// access view (UAV) descriptor heap.
D3D12_DESCRIPTOR_HEAP_DESC UavHeapDesc = {};
UavHeapDesc.NumDescriptors = DescriptorCount;
UavHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
UavHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
DX::ThrowIfFailed(m_device->CreateDescriptorHeap(&UavHeapDesc, IID_PPV_ARGS(&m_UavHeap)));
NAME_D3D12_OBJECT(m_UavHeap);
m_UavDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}
std::cout << " Creating a command allocator for each frame" << std::endl;
// Create a command allocator for each frame.
for (UINT n = 0; n < FrameCount; n++) {
DX::ThrowIfFailed(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocators[n])));
}
} // Load the rendering pipeline dependencies.
std::cout << "Loading the sample assets" << std::endl;
// Load the sample assets.
{
std::cout << " Creating the pipeline states, including compiling and loading shaders" << std::endl;
// Create the pipeline states, which includes compiling and loading shaders.
{
Microsoft::WRL::ComPtr<ID3DBlob> computeShader;
#if defined(_DEBUG)
// Enable better shader debugging with the graphics debugging tools.
UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
#else
UINT compileFlags = 0;
#endif
// Load and compile the compute shader.
DX::ThrowIfFailed(D3DReadFileToBlob(L"ComputeShader.cso", &computeShader));
auto convert_blob_to_byte = [](Microsoft::WRL::ComPtr<ID3DBlob> blob) {
auto* p = reinterpret_cast<unsigned char*>(blob->GetBufferPointer());
auto n = blob->GetBufferSize();
std::vector<unsigned char> buff;
buff.reserve(n);
std::copy(p, p + n, std::back_inserter(buff));
return buff;
};
std::vector<BYTE> m_computeShader = convert_blob_to_byte(computeShader);
// Describe and create the compute pipeline state object (PSO).
D3D12_COMPUTE_PIPELINE_STATE_DESC computePsoDesc = {};
computePsoDesc.pRootSignature = m_computeRootSignature.Get();
computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(computeShader.Get());
DX::ThrowIfFailed(m_device->CreateComputePipelineState(&computePsoDesc, IID_PPV_ARGS(&m_computeState)));
NAME_D3D12_OBJECT(m_computeState);
}
std::cout << " Creating the command list" << std::endl;
// Create the command list.
DX::ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocators[m_frameIndex].Get(), m_computeState.Get(), IID_PPV_ARGS(&m_commandList)));
NAME_D3D12_OBJECT(m_commandList);
std::cout << " Initializing the data in the buffers" << std::endl;
// Initialize the data in the buffers.
{
data.resize(2);
for (unsigned int i = 0; i < data.size(); i++) {
data[i] = 0.0f;
}
const UINT dataSize = data.size() * sizeof(data[0]);
D3D12_HEAP_PROPERTIES defaultHeapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);
D3D12_HEAP_PROPERTIES uploadHeapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD);
D3D12_HEAP_PROPERTIES readbackHeapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK);
D3D12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(dataSize, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
D3D12_RESOURCE_DESC uploadBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(dataSize);
readbackBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(dataSize);
DX::ThrowIfFailed(m_device->CreateCommittedResource(
&defaultHeapProperties,
D3D12_HEAP_FLAG_NONE,
&bufferDesc,
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
IID_PPV_ARGS(&m_dataBuffer)));
m_dataBuffer.Get()->SetName(L"m_dataBuffer");
DX::ThrowIfFailed(m_device->CreateCommittedResource(
&uploadHeapProperties,
D3D12_HEAP_FLAG_NONE,
&uploadBufferDesc,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&m_dataBufferUpload)));
m_dataBufferUpload.Get()->SetName(L"m_dataBufferUpload");
DX::ThrowIfFailed(m_device->CreateCommittedResource(
&readbackHeapProperties,
D3D12_HEAP_FLAG_NONE,
&readbackBufferDesc,
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
IID_PPV_ARGS(&m_dataBufferReadback)));
m_dataBufferReadback.Get()->SetName(L"m_dataBufferReadback");
NAME_D3D12_OBJECT(m_dataBuffer);
dataSubResource = {};
dataSubResource.pData = &data[0];
dataSubResource.RowPitch = dataSize;
dataSubResource.SlicePitch = dataSubResource.RowPitch;
UpdateSubresources<1>(m_commandList.Get(), m_dataBuffer.Get(), m_dataBufferUpload.Get(), 0, 0, 1, &dataSubResource);
m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_dataBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COMMON));
m_commandList->CopyResource(m_dataBufferReadback.Get(), m_dataBufferUpload.Get());
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
uavDesc.Format = DXGI_FORMAT_UNKNOWN;
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
uavDesc.Buffer.FirstElement = 0;
uavDesc.Buffer.NumElements = 1;
uavDesc.Buffer.StructureByteStride = sizeof(data[0]);
uavDesc.Buffer.CounterOffsetInBytes = 0;
uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE;
CD3DX12_CPU_DESCRIPTOR_HANDLE uavHandle0(m_UavHeap->GetCPUDescriptorHandleForHeapStart(), Uav, m_UavDescriptorSize);
m_device->CreateUnorderedAccessView(m_dataBuffer.Get(), nullptr, &uavDesc, uavHandle0);
} // Initialize the data in the buffers.
std::cout << " Closing the command list and executing it to begind the initial GPU setup" << std::endl;
// Close the command list and execute it to begin the initial GPU setup.
DX::ThrowIfFailed(m_commandList->Close());
ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
std::cout << " Creating synchronization objects and wait until assets have been uploaded to the GPU" << std::endl;
// Create synchronization objects and wait until assets have been uploaded to the GPU.
{
DX::ThrowIfFailed(m_device->CreateFence(m_renderContextFenceValue, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_renderContextFence)));
m_renderContextFenceValue++;
m_renderContextFenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
if (m_renderContextFenceEvent == nullptr) {
DX::ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError()));
}
// Add a signal command to the queue.
DX::ThrowIfFailed(m_commandQueue->Signal(m_renderContextFence.Get(), m_renderContextFenceValue));
// Instruct the fence to set the event object when the signal command completes.
DX::ThrowIfFailed(m_renderContextFence->SetEventOnCompletion(m_renderContextFenceValue, m_renderContextFenceEvent));
m_renderContextFenceValue++;
// Wait until the signal command has been processed.
WaitForSingleObject(m_renderContextFenceEvent, INFINITE);
}
} // Load the sample assets.
std::cout << "Creating compute resources" << std::endl;
{
// Create compute resources.
D3D12_COMMAND_QUEUE_DESC queueDesc = { D3D12_COMMAND_LIST_TYPE_COMPUTE, 0, D3D12_COMMAND_QUEUE_FLAG_NONE };
DX::ThrowIfFailed(m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_computeCommandQueue)));
DX::ThrowIfFailed(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_COMPUTE, IID_PPV_ARGS(&m_computeAllocator)));
DX::ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_COMPUTE, m_computeAllocator.Get(), nullptr, IID_PPV_ARGS(&m_computeCommandList)));
DX::ThrowIfFailed(m_device->CreateFence(0, D3D12_FENCE_FLAG_SHARED, IID_PPV_ARGS(&m_Fence)));
m_FenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
if (m_FenceEvent == nullptr) {
DX::ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError()));
}
}
std::cout << "Calculating" << std::endl;
Calculate();
std::cout << "Finished" << std::endl;
}
void myClass::Calculate() {
m_computeCommandList.Get()->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_dataBuffer.Get(), D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_UNORDERED_ACCESS));
m_computeCommandList.Get()->SetPipelineState(m_computeState.Get());
m_computeCommandList.Get()->SetComputeRootSignature(m_computeRootSignature.Get());
ID3D12DescriptorHeap* ppHeaps[] = { m_UavHeap.Get() };
m_computeCommandList.Get()->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);
CD3DX12_GPU_DESCRIPTOR_HANDLE uavHandle(m_UavHeap->GetGPUDescriptorHandleForHeapStart(), Uav, m_UavDescriptorSize);
m_computeCommandList.Get()->SetComputeRootUnorderedAccessView(ComputeRootUAVTable, m_dataBuffer->GetGPUVirtualAddress());
m_computeCommandList.Get()->Dispatch(1, 1, 1);
m_computeCommandList.Get()->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_dataBuffer.Get(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COMMON));
// Close and execute the command list.
DX::ThrowIfFailed(m_computeCommandList.Get()->Close());
ID3D12CommandList* commandLists[] = { m_computeCommandList.Get() };
m_computeCommandQueue->ExecuteCommandLists(1, commandLists);
// Wait for the compute shader to complete the calculation.
UINT64 FenceValue = InterlockedIncrement(&m_FenceValue);
DX::ThrowIfFailed(m_computeCommandQueue.Get()->Signal(m_Fence.Get(), FenceValue));
DX::ThrowIfFailed(m_Fence.Get()->SetEventOnCompletion(FenceValue, m_FenceEvent));
WaitForSingleObject(m_FenceEvent, INFINITE);
std::cout << "FenceValue = " << FenceValue << " " << m_FenceValue << " " << m_Fence.Get()->GetCompletedValue() << std::endl;
// Check the output!
float* dataptr = nullptr;
D3D12_RANGE range = { 0, readbackBufferDesc.Width };
DX::ThrowIfFailed(m_dataBufferReadback->Map(0, &range, (void**)&dataptr));
for (int i = 0; i < readbackBufferDesc.Width / sizeof(data[0]); i++)
printf("uav[%d] = %.2f\n", i, dataptr[i]);
m_dataBufferReadback->Unmap(0, nullptr);
for (unsigned int i = 0; i < data.size(); i++) {
std::cout << "data[" << i << "] = " << data[i] << std::endl;
}
}
myClass.h:
#pragma once
#include "Common\Device.h"
#include <iostream>
// We have to write all of this as its own class, otherwise we cannot
// use the "this" pointer when we create compute resources. We need to
// do that because this code tagets multithreading.
class myClass {
public:
myClass();
private:
// Two buffers full of data are used. The compute thread alternates
// writing to each of them. The render thread renders using the
// buffer that is not currently in use by the compute shader.
//struct Data {
// float c;
//};
//std::vector<Data> data;
std::vector<float> data;
// For the compute pipeline, the CBV is a struct containing some
// constants used in the compute shader.
struct ConstantBufferCS {
float a;
float b;
};
D3D12_SUBRESOURCE_DATA dataSubResource;
static const UINT FrameCount = 1;
//static const UINT ThreadCount = 1;
UINT m_heightInstances;
UINT m_widthInstances;
UINT m_frameIndex;
Microsoft::WRL::ComPtr<ID3D12RootSignature> m_rootSignature;
Microsoft::WRL::ComPtr<ID3D12RootSignature> m_computeRootSignature;
Microsoft::WRL::ComPtr<ID3D12CommandQueue> m_commandQueue;
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> m_UavHeap;
Microsoft::WRL::ComPtr<ID3D12CommandAllocator> m_commandAllocators[FrameCount];
Microsoft::WRL::ComPtr<ID3D12PipelineState> m_computeState;
Microsoft::WRL::ComPtr<ID3D12GraphicsCommandList> m_commandList;
Microsoft::WRL::ComPtr<ID3D12Resource> m_constantBufferCS;
UINT64 m_renderContextFenceValue;
HANDLE m_renderContextFenceEvent;
UINT64 m_frameFenceValues[FrameCount];
UINT m_UavDescriptorSize;
ConstantBufferCS constantBufferCS;
Microsoft::WRL::ComPtr<ID3D12Resource> constantBufferCSUpload;
Microsoft::WRL::ComPtr<ID3D12Fence> m_renderContextFence;
Microsoft::WRL::ComPtr<ID3D12Resource> m_dataBuffer;
Microsoft::WRL::ComPtr<ID3D12Resource> m_dataBufferUpload;
Microsoft::WRL::ComPtr<ID3D12Resource> m_dataBufferReadback;
// Compute objects.
Microsoft::WRL::ComPtr<ID3D12CommandAllocator> m_computeAllocator;
Microsoft::WRL::ComPtr<ID3D12CommandQueue> m_computeCommandQueue;
Microsoft::WRL::ComPtr<ID3D12GraphicsCommandList> m_computeCommandList;
Microsoft::WRL::ComPtr<ID3D12Fence> m_Fence;
volatile HANDLE m_FenceEvent;
D3D12_RESOURCE_DESC readbackBufferDesc;
// State
UINT64 volatile m_FenceValue;
/*
struct ThreadData {
myClass* pContext;
UINT threadIndex;
};
ThreadData m_threadData;
HANDLE m_threadHandles;
*/
void Calculate();
// Indices of shader resources in the descriptor heap.
enum DescriptorHeapIndex : UINT32 {
Uav = 0,
DescriptorCount = 1
};
enum ComputeRootParameters : UINT32 {
//ComputeRootCBV = 0,
ComputeRootUAVTable = 0,
ComputeRootParametersCount
};
};
Device.cpp:
#pragma once
#include "pch.h"
#include "Device.h"
#include "DirectXHelper.h"
#include <cassert> // for "assert"
#include <iostream>
static Device* gs_pSingelton = nullptr;
// Constructor
Device::Device(HINSTANCE hInst, bool useWarp)
: m_hInstance(hInst)
, m_useWarp(useWarp)
{
}
void Device::Initialize() {
#if defined(_DEBUG)
// Always enable the debug layer before doing anything DX12 related
// so all possible errors generated while creating DX12 objects
// are caught by the debug layer.
Microsoft::WRL::ComPtr<ID3D12Debug1> debugInterface;
DX::ThrowIfFailed(D3D12GetDebugInterface(IID_PPV_ARGS(&debugInterface)));
debugInterface->EnableDebugLayer();
// Enable these if you want full validation (will slow down rendering a lot).
//debugInterface->SetEnableGPUBasedValidation(TRUE);
//debugInterface->SetEnableSynchronizedCommandQueueValidation(TRUE);
#endif
auto dxgiAdapter = GetAdapter(false);
if (!dxgiAdapter) { // If no supporting DX12 adapters exist, fall back to WARP
dxgiAdapter = GetAdapter(true);
}
if (dxgiAdapter) {
m_device = CreateDevice(dxgiAdapter);
}
else {
throw std::exception("DXGI adapter enumeration failed.");
}
}
void Device::Create(HINSTANCE hInst) {
if (!gs_pSingelton) {
gs_pSingelton = new Device(hInst);
gs_pSingelton->Initialize();
}
}
Device& Device::Get() {
assert(gs_pSingelton);
return *gs_pSingelton;
}
void Device::Destroy() {
if (gs_pSingelton) {
delete gs_pSingelton;
gs_pSingelton = nullptr;
}
}
// Destructor
Device::~Device() {
}
Microsoft::WRL::ComPtr<ID3D12Device2> Device::CreateDevice(Microsoft::WRL::ComPtr<IDXGIAdapter4> adapter) {
Microsoft::WRL::ComPtr<ID3D12Device2> d3d12Device2;
DX::ThrowIfFailed(D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&d3d12Device2)));
// Enable debug messages in debug mode.
#if defined(_DEBUG)
Microsoft::WRL::ComPtr<ID3D12InfoQueue> pInfoQueue;
if (SUCCEEDED(d3d12Device2.As(&pInfoQueue))) {
pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, TRUE);
pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, TRUE);
pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, TRUE);
// Suppress whole categories of messages
//D3D12_MESSAGE_CATEGORY Categories[] = {};
// Suppress messages based on their severity level
D3D12_MESSAGE_SEVERITY Severities[] = { D3D12_MESSAGE_SEVERITY_INFO };
// Suppress individual messages by their ID
D3D12_MESSAGE_ID DenyIds[] = {
D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE, // I'm really not sure how to avoid this message.
D3D12_MESSAGE_ID_MAP_INVALID_NULLRANGE, // This warning occurs when using capture frame while graphics debugging.
D3D12_MESSAGE_ID_UNMAP_INVALID_NULLRANGE, // This warning occurs when using capture frame while graphics debugging.
};
D3D12_INFO_QUEUE_FILTER NewFilter = {};
//NewFilter.DenyList.NumCategories = _countof(Categories);
//NewFilter.DenyList.pCategoryList = Categories;
NewFilter.DenyList.NumSeverities = _countof(Severities);
NewFilter.DenyList.pSeverityList = Severities;
NewFilter.DenyList.NumIDs = _countof(DenyIds);
NewFilter.DenyList.pIDList = DenyIds;
DX::ThrowIfFailed(pInfoQueue->PushStorageFilter(&NewFilter));
}
#endif
return d3d12Device2;
}
Microsoft::WRL::ComPtr<IDXGIAdapter4> Device::GetAdapter(bool useWarp) {
UINT createFactoryFlags = 0;
#if defined(_DEBUG)
createFactoryFlags = DXGI_CREATE_FACTORY_DEBUG;
#endif
DX::ThrowIfFailed(CreateDXGIFactory2(createFactoryFlags, IID_PPV_ARGS(&m_factory)));
Microsoft::WRL::ComPtr<IDXGIAdapter1> dxgiAdapter1;
Microsoft::WRL::ComPtr<IDXGIAdapter4> dxgiAdapter4;
if (useWarp) {
DX::ThrowIfFailed(m_factory->EnumWarpAdapter(IID_PPV_ARGS(&dxgiAdapter1)));
DX::ThrowIfFailed(dxgiAdapter1.As(&dxgiAdapter4));
}
else {
SIZE_T maxDedicatedVideoMemory = 0;
for (UINT i = 0; m_factory->EnumAdapters1(i, &dxgiAdapter1) != DXGI_ERROR_NOT_FOUND; ++i) {
DXGI_ADAPTER_DESC1 dxgiAdapterDesc1;
dxgiAdapter1->GetDesc1(&dxgiAdapterDesc1);
// Check to see if the adapter can create a D3D12 device without actually
// creating it. The adapter with the largest dedicated video memory
// is favored.
if ((dxgiAdapterDesc1.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) == 0 &&
SUCCEEDED(D3D12CreateDevice(dxgiAdapter1.Get(),
D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), nullptr)) &&
dxgiAdapterDesc1.DedicatedVideoMemory > maxDedicatedVideoMemory) {
maxDedicatedVideoMemory = dxgiAdapterDesc1.DedicatedVideoMemory;
DX::ThrowIfFailed(dxgiAdapter1.As(&dxgiAdapter4));
}
}
}
return dxgiAdapter4;
}
Device.h:
#pragma once
#include <dxgi1_6.h> // IDXGIAdapter4
// We require this file because we are unable to pass the device pointer to everywhere we need to.
class Device {
public:
/**
* Create the device singleton with the device instance handle.
*/
static void Create(HINSTANCE hInst);
/**
* Destroy the device instance.
*/
static void Destroy();
/**
* Get the device singleton.
*/
static Device& Get();
/**
* Get the Direct3D 12 device
*/
Microsoft::WRL::ComPtr<ID3D12Device2> GetDevice() const { return m_device; }
Microsoft::WRL::ComPtr<IDXGIFactory4> GetFactory() const { return m_factory; }
protected:
// Create a device instance
Device(HINSTANCE hInst, bool useWarp = false);
// Destroy the device instance.
virtual ~Device();
// Initialize the device instance.
void Initialize();
Microsoft::WRL::ComPtr<IDXGIAdapter4> GetAdapter(bool useWarp);
Microsoft::WRL::ComPtr<ID3D12Device2> CreateDevice(Microsoft::WRL::ComPtr<IDXGIAdapter4> adapter);
private:
Device(const Device& copy) = delete;
Device& operator=(const Device& other) = delete;
HINSTANCE m_hInstance;
Microsoft::WRL::ComPtr<ID3D12Device2> m_device;
Microsoft::WRL::ComPtr<IDXGIFactory4> m_factory;
bool m_useWarp;
};
ComputeShader.hlsl:
RWStructuredBuffer<float> output : register(u0); // UAV
[numthreads(1, 1, 1)]
void main( uint3 DTid : SV_DispatchThreadID ) {
output[DTid.x] = 1 + 1;
}
Please let me know if you are able to find what I do not understand. I can also try uploading my project to GitHub if it helps... SOS :(
Related
Running MacOS Catalina and VSCode.
This is how I initialize my device
void Renderer::InitDevice() {
{
uint32_t gpu_count = 0;
vkEnumeratePhysicalDevices(Instance, &gpu_count, nullptr);
std::vector<VkPhysicalDevice> gpu_list(gpu_count);
vkEnumeratePhysicalDevices(Instance, &gpu_count, gpu_list.data()); //populates gpu_list with all gpu handles
GPU = gpu_list[0]; //grab first gpu. debug and figure out a ranking system
vkGetPhysicalDeviceProperties(GPU, &GPU_device_properties);
}
{
uint32_t family_count = 0;
vkGetPhysicalDeviceQueueFamilyProperties(GPU, &family_count, nullptr);
std::vector<VkQueueFamilyProperties> family_properties(family_count);
vkGetPhysicalDeviceQueueFamilyProperties(GPU, &family_count, family_properties.data());
bool found_graphics_bit = false;
for ( u_int32_t i = 0; i<family_count; i++){
if(family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT){
found_graphics_bit = true;
graphics_family_index = i;
}
}
if (!found_graphics_bit){
assert(1 && "Vulkan Error: Queue family supporting graphics card not found");
std::exit(-1);
}
}
{
uint32_t layer_count = 0;
vkEnumerateInstanceLayerProperties(&layer_count, nullptr);
std::vector<VkLayerProperties> layer_properties(layer_count);
vkEnumerateInstanceLayerProperties(&layer_count, layer_properties.data()); //something about system layers
std::cout << "Instance Layers: \n";
for (auto &layer_property: layer_properties){
std::cout << "\t" << layer_property.layerName << "\n";
std::cout << "\t\t" << layer_property.description << "\n";
}
std::cout << "\n";
}
{
uint32_t layer_count = 0;
vkEnumerateDeviceLayerProperties(GPU, &layer_count, nullptr);
std::vector<VkLayerProperties> layer_properties(layer_count);
vkEnumerateDeviceLayerProperties(GPU, &layer_count, layer_properties.data()); //something about system layers
std::cout << "Device Layers: \n";
for (auto &layer_property: layer_properties){
std::cout << "\t" << layer_property.layerName << "\n";
std::cout << "\t\t" << layer_property.description << "\n";
}
std::cout << "\n";
}
float queue_priorities[] { 1.0f };
VkDeviceQueueCreateInfo device_queue_info = {};
//need to understand queue properties
device_queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
device_queue_info.queueFamilyIndex = graphics_family_index;
device_queue_info.queueCount = 1;
device_queue_info.pQueuePriorities = queue_priorities;
VkDeviceCreateInfo device_info{};
device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
device_info.queueCreateInfoCount = 1;
device_info.pQueueCreateInfos = &device_queue_info;
device_info.enabledLayerCount = device_layers.size();
device_info.ppEnabledLayerNames = device_layers.data();
device_info.enabledExtensionCount = device_extensions.size();
device_info.ppEnabledExtensionNames = device_extensions.data();
auto err = vkCreateDevice(GPU, &device_info, nullptr, &Device);
if (err != VK_SUCCESS){
assert(1 && "Vulkan Error: Device Creation Failed");
std::exit(-1);
}
}
Vulkan device creation return VK_SUCCESS when this error occurs.
And this is how I destroy it
void Renderer::DeinitDevice() {
vkDeviceWaitIdle(Device);
vkDestroyDevice(Device, nullptr); //uncommenting this causes program to crash.
Device = nullptr;
}
on vkDeviceWaitIdle(Device); or if that is removed it happens on vkDestroyDevice(Device, nullptr);
I get EXC_BAD_ACCESS
and
#"2020-05-17 15:06:54.832625-0400 main[4816:29494] flock failed to lock maps file: errno = 35\r\n"
#"UNASSIGNED-ObjectTracker-ObjectLeak(ERROR / SPEC): msgNum: 699204130 - Validation Error: [ UNASSIGNED-ObjectTracker-ObjectLeak ] Object 0: handle = 0x10104e018, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0x29ad0222 | OBJ ERROR : VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT object VkDevice 0x10104e018[] has not been destroyed.\r\n"
#" Objects: 1\r\n"
#" [0] 0x10104e018, type: 3, name: NULL\r\n"
I was following the vulkan-tutorial and I couldn't really understand that but I found a few videos that explained the things the tutorial really doesn't go over. So far I've put this together but I'm not sure what's causing the error. I've seen other similar errors but can't seem to find out how they fixed it.
The code I didn't post that actually contained the issue was this
Renderer::~Renderer(){
DestroyInstance();
DeinitDevice();
}
I transposed these two from the tutorial I was following on accident. and should be this
Renderer::~Renderer(){
DeinitDevice();
DestroyInstance();
}
How do I take images with Sapera SDK and transfer the image data from the SapBuffer object to vector?
To handle images taken by camera using Sapera, you should make specialization of SapProcessing class, which is used to process buffers. Otherwise the buffer is cleared automatically after each frame, and you lose the data.
The imaging process goes as follows:
You call Grab() on the camera object to start imaging
After each frame has been taken, transfer callback is called. Here you request your SapProcessing object to process the next frame.
Run() function of your SapProcessing object is called. Here you can read data from the buffer.
After Run() function, processing callback is called.
When you have received enough frames, call Freeze() to stop imaging.
This example code takes images using default settings on the camera (monochrome 8-bit pixel format).
#include <string>
#include <vector>
#include <memory>
#include <stdexcept>
#include <iostream>
#include <iomanip>
#include <atomic>
#include "SapClassBasic.h"
// Helper function to find the camera by its serial number
SapAcqDevice getDeviceBySN(const std::string& sn)
{
char serverName[CORSERVER_MAX_STRLEN];
char serialNumberName[2048];
const int serverCount = SapManager::GetServerCount();
for (int i = 0; i < serverCount; i++) {
if (SapManager::GetResourceCount(i, SapManager::ResourceAcqDevice) != 0)
{
SapManager::GetServerName(i, serverName, sizeof(serverName));
SapAcqDevice camera(serverName);
if (!camera.Create()) {
throw std::runtime_error("Failed to create camera object.");
}
int featureCount;
if (camera.GetFeatureCount(&featureCount) && featureCount > 0)
{
if (camera.GetFeatureValue("DeviceID", serialNumberName, sizeof(serialNumberName))
&& serialNumberName == sn)
{
return camera;
}
}
camera.Destroy();
}
}
const auto errorStr = "Camera \"" + sn + "\" was not found.";
throw std::runtime_error(errorStr.c_str());
}
class SapMyProcessing : public SapProcessing
{
public:
SapMyProcessing(SapBuffer* pBuffers, SapProCallback pCallback, void* pContext);
virtual ~SapMyProcessing();
protected:
virtual BOOL Run();
};
SapMyProcessing::SapMyProcessing(SapBuffer* pBuffers, SapProCallback pCallback, void* pContext)
: SapProcessing(pBuffers, pCallback, pContext)
{}
SapMyProcessing::~SapMyProcessing()
{
if (m_bInitOK) Destroy();
}
BOOL SapMyProcessing::Run()
{
// Get the current buffer index
const int proIndex = GetIndex();
// If this is not true, buffer has overflown
SapBuffer::State state;
bool goodContent = m_pBuffers->GetState(proIndex, &state)
&& state == SapBuffer::StateFull;
if (goodContent) {
void *inAddress = nullptr;
m_pBuffers->GetAddress(proIndex, &inAddress);
int inSize = 0;
m_pBuffers->GetSpaceUsed(proIndex, &inSize);
// Width, height and pixel format are received from the camera
const int width = m_pBuffers->GetWidth();
const int height = m_pBuffers->GetHeight();
const auto format = m_pBuffers->GetFormat();
const int outSize = width * height;
// Skip unexpected pixel format or incomplete frame
goodContent = format == SapFormatMono8
&& inSize == outSize;
if (goodContent) {
// Copy data to vector
std::vector<uint8_t> outBuffer(outSize);
std::copy((uint8_t*)inAddress, (uint8_t*)(inAddress) + outSize, outBuffer.begin());
// Print the first line
for (int i = 0; i < width; i++) {
std::cout << std::hex << int(outBuffer[i]);
}
std::cout << std::endl << std::endl;
}
}
return TRUE;
}
// Information to pass to callbacks
struct TransferContext {
std::atomic_int frameGrabCount = 0, frameProcessingCount = 0;
std::shared_ptr<SapMyProcessing> processing;
};
void transferCallback(SapXferCallbackInfo *info)
{
auto context = (TransferContext*)info->GetContext();
context->frameGrabCount++;
if (!info->IsTrash()) {
// Execute Run() for this frame
context->processing->ExecuteNext();
}
}
// Processing callback is called after Run()
void processingCallback(SapProCallbackInfo* info)
{
auto context = (TransferContext*)info->GetContext();
// Processing has finished
context->frameProcessingCount++;
}
// The main imaging function
void grab(const std::string& serialNumber)
{
// Number of frames to receive from the camera
const int maxFrameCount = 10;
TransferContext context;
auto camera = getDeviceBySN(serialNumber);
std::unique_ptr<SapBuffer> buffer
= std::make_unique<SapBufferWithTrash>(maxFrameCount, &camera);
std::unique_ptr<SapTransfer> transfer
= std::make_unique<SapAcqDeviceToBuf>(&camera, buffer.get(), transferCallback, &context);
context.processing = std::make_shared<SapMyProcessing>(buffer.get(), processingCallback, &context);
auto cleanup = [&]() {
if (context.processing) context.processing->Destroy();
if (transfer) transfer->Destroy();
if (buffer) buffer->Destroy();
camera.Destroy();
};
try {
if (!buffer->Create()) {
throw std::runtime_error("Failed to create buffer object.");
}
if (!transfer->Create()) {
throw std::runtime_error("Failed to create transfer object.");
}
if (!context.processing->Create()) {
throw std::runtime_error("Failed to create processing object.");
}
transfer->SetAutoEmpty(false);
context.processing->SetAutoEmpty(true);
context.processing->Init();
transfer->Grab();
// Wait for the camera to grab all frames
while (context.frameGrabCount < maxFrameCount);
transfer->Freeze();
if (!transfer->Wait(5000)) {
throw std::runtime_error("Failed to stop grab.");
}
// Wait for processing to complete
while (context.frameProcessingCount < maxFrameCount);
cleanup();
}
catch (...) {
cleanup();
throw;
}
}
I have built a Qt (5.7) application that interfaces with the Windows Media Player COM API to parse track meta data. For some in-explicit reason my application is crashing when calling into IWMPMedia3::getAttributeCountByType.
The line where the crash keeps occurring is:
if (pMedia3Item && pMedia3Item->getAttributeCountByType(L"TrackingID", 0, &l) == S_OK) //Will eventually crash here
It does not crash on the first instance, it takes a couple of hundred loops and seems to be connected to when the call repeatedly returns 0. If I switch to an attribute that I know exists then it runs fine.
What is posted below is the object stripped right back, but it still crashes. This object is designed to run in its own QThread and all the COM symbols are defined and contained within the QThread.
The code forms part of a larger app that makes use of many other Qt modules, GUI, web engine being two of the biggest.
#include "WMPMLImport.h"
#include <QDebug>
#include "Wininet.h"
#define WMP_CLSID L"{6BF52A52-394A-11d3-B153-00C04F79FAA6}"
#define WMP_REFIID L"{D84CCA99-CCE2-11d2-9ECC-0000F8085981}"
#define WMP_PL_ALL_MUSIC L"All Music"
#define SAFE_RELEASE(ptr) if(NULL!=(ptr)){(ptr)->Release();ptr=NULL;}
#define BSTR_RELEASE(bstr) {SysFreeString(bstr);(bstr)=NULL;}
class CCoInitialize
{
public:
CCoInitialize() :
m_hr(CoInitialize(NULL))
{}
~CCoInitialize()
{
if(SUCCEEDED(m_hr)) {
qDebug() << "CCoInitialize: DTOR";
CoUninitialize();
}
}
HRESULT m_hr;
};
/**
Worker class that will step through the WMP COM interface
and extact the audio meta data contained within it,
*/
class WMPMLComHandler : public QObject
{
public:
WMPMLComHandler(WMPMLImport* t) :
m_thread(t)
{
qDebug() << "WMPMLComHandler::CTOR" << QThread::currentThreadId();
}
~WMPMLComHandler()
{
qDebug() << "WMPMLComHandler::DTOR" << QThread::currentThreadId();
}
/**
Method responsible for walking through the COM interface and extracting
all the track and playlist metadata including the artwork.
#returns Return false if the COM API was not parsed correctly.
*/
bool parse()
{
bool b = true;
CCoInitialize cCoInit;
IWMPCore* pIWMPCore = NULL;
IWMPCore3* pIWMPCore3 = NULL;
IWMPPlaylistCollection *pPlaylistCollection;
IWMPPlaylist *pMainLibplaylist;
CLSID clsID;
CLSID refID;
CLSIDFromString(WMP_CLSID, &clsID);
CLSIDFromString(WMP_REFIID, &refID);
if(SUCCEEDED(CoCreateInstance(clsID, NULL, CLSCTX_ALL, refID, (void**)&pIWMPCore)))
{
if(SUCCEEDED(pIWMPCore->get_playlistCollection(&pPlaylistCollection)))
{
if(SUCCEEDED(pIWMPCore->QueryInterface(__uuidof(IWMPCore3), reinterpret_cast<void**>(&pIWMPCore3))))
{
IWMPPlaylistArray* pPlaylistArray = NULL;
if(SUCCEEDED(pPlaylistCollection->getAll(&pPlaylistArray)))
{
long playlistCount = 0;
if(SUCCEEDED(pPlaylistArray->get_count(&playlistCount)))
{
IWMPPlaylist* pPlaylist = NULL;
for(int playlistIndex=0; playlistIndex < playlistCount; playlistIndex++)
{
if (SUCCEEDED(pPlaylistArray->item(playlistIndex, &pPlaylist)))
{
long lMediaCount = 0;
if (SUCCEEDED(pPlaylist->get_count(&lMediaCount)))
{
fetchPlaylist(pPlaylist, NULL, playlistIndex, lMediaCount);
}
SAFE_RELEASE(pPlaylist);
}
}
}
SAFE_RELEASE(pPlaylistArray);
}
SAFE_RELEASE(pIWMPCore3);
}
SAFE_RELEASE(pPlaylistCollection);
}
SAFE_RELEASE(pIWMPCore);
}
SAFE_RELEASE(pMainLibplaylist);
return b;
}
private:
void fetchPlaylist(IWMPPlaylist* pPlaylist, BSTR bstrName, unsigned int playlistIndex, long count)
{
//get the playlist items
for(long mediaIndex=0; mediaIndex<count-1; mediaIndex++)
{
IWMPMedia* pMediaItem = NULL;
if(SUCCEEDED(pPlaylist->get_item(mediaIndex, &pMediaItem)))
{
IWMPMedia3 *pMedia3Item = NULL;
if (pMediaItem->QueryInterface(__uuidof(IWMPMedia3), reinterpret_cast<void **>(&pMedia3Item)) == S_OK)
{
long l = 0;
qDebug() << "About to call method for" << mediaIndex << "time";
if (pMedia3Item && pMedia3Item->getAttributeCountByType(L"TrackingID", 0, &l) == S_OK) //Will eventually crash here
{
qDebug() << "Exited method for" << mediaIndex << "time";
}
}
SAFE_RELEASE(pMedia3Item);
SAFE_RELEASE(pMediaItem);
}
}
qDebug() << "*********COMPLETE*********";
}
WMPMLImport* m_thread;
};
//==
WMPMLImport::WMPMLImport() :
m_comHandler(NULL)
{
qDebug() << "WMPMLImporter CTOR" << QThread::currentThreadId();
}
WMPMLImport::~WMPMLImport()
{
}
/**
Reimplemented function that runs the function contents in a new thread context.
The parsing of the COM is all ran through this thread. Returning out of this
thread will end its execution.
*/
void WMPMLImport::run()
{
QMutexLocker g(&m_lock);
m_comHandler = new WMPMLComHandler(this);
g.unlock();
bool parseOk = m_comHandler->parse();
g.relock();
delete m_comHandler;
m_comHandler = NULL;
}
I have a 3rd party .dll (and relative .h and .lib) to control a device via USB.
I want to use the dll functions into a class (AOTF_controller) to implement my desired behaviour.
What I want to do is :
Connect to the device (connect() class function);
Initialize it (init() class function);
Set some parameters (setScanningFreq() class function)
Increase sequentially the frequency of my device (increaseFreq() class function)
Reset and close the USB connection.
I can obtain this behavior when I use the dll functions directly into the _tmain() therefore the device works correctly, but when I wrap the dll functions into a class and try to use the class something goes wrong.
I repeat the above process (list item 1-5) several times: sometimes it works fine, sometimes the program stop and the debugger gives me this error:
First-chance exception at 0x77533fb7 in AOTFcontrollerDebug.exe: 0xC0150014: The activation context activation stack for the running thread of execution is corrupt.
The error seems random, sometimes I can conclude 80 times the scan without any problem, sometimes it gives me error right at the first scan.
I tried to search for that error but I was not able to find anything useful.
Anyone can help? I guess could be related on how the dll functions are called in my class?
Here is the main function code:
// AOTFcontrollerDebug.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "AOTFcontrollerDebug.h"
#include "AOTF_Controller.h"
#include <iostream>
#include <string>
#include <sstream>
#include <AotfLibrary.h>
#define DEFAULT_STARTFREQUENCY 78
#define DEFAULT_ENDFREQUENCY 95.5
#define DEFAULT_NUMOFFRAMES 256
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// The one and only application object
CWinApp theApp;
using namespace std;
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
HMODULE hModule = ::GetModuleHandle(NULL);
if (hModule != NULL)
{
// initialize MFC and print and error on failure
if (!AfxWinInit(hModule, NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: MFC initialization failed\n"));
nRetCode = 1;
}
else
{
// TODO: code your application's behavior here.
std::cout << "-----AOTF Controller Debugging-----"<<endl;
//input of scans to do
int repeatedScan;
std::cout << "Type how many repeated scan: "<<endl;
std::cin >> repeatedScan;
//instance
AOTF_Controller m_AOTF_Controller;
std::cout << "AOTF Controller instance done..."<<endl;
//loop over scans
for(int i =0;i<repeatedScan;i++)
{
m_AOTF_Controller.connect();
std::cout << "AOTF Controller connected..."<<endl;
std::cout << "Scan number : "<< (i + 1) <<endl;
m_AOTF_Controller.init();
//set the delta freq to increase at each step
m_AOTF_Controller.setScanningFreq(DEFAULT_STARTFREQUENCY, DEFAULT_ENDFREQUENCY, DEFAULT_NUMOFFRAMES);
//loop over wavelengths
int sleep_ms = 4;
for (int j =0; j <DEFAULT_NUMOFFRAMES; j++)
{
Sleep(sleep_ms) ;
m_AOTF_Controller.increaseFreq();
//std::cout << " "<< (j + 1) ;
}
// terminate scans
m_AOTF_Controller.reset();
m_AOTF_Controller.disconnect();
std::cout << endl <<"Scan number "<< (i + 1) << "terminated successfully" <<endl;
Sleep(sleep_ms*100) ;
}
}
}
else
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: GetModuleHandle failed\n"));
nRetCode = 1;
}
return nRetCode;
}
and here the Aotf_Controller class code:
//Aotf_Controller.h
#pragma once
#include <AotfLibrary.h>
#include <string>
#include <sstream>
#include <iomanip>
#define CONVERSION_MHZ_TO_HZ 1000000
class AOTF_Controller
{
private:
enum Error {SUCCESSFUL , CONNECTION_ERROR, DISCONNECTION_ERROR, INIT_ERROR, RESET_ERROR , SET_ERROR }; // error enum values
HANDLE hAotfController;
int currentGain;
long currentFreq; // current frequency in Hz
long startFreq, endFreq, deltaFreq; // frequency values for the scanning in Hz
public:
AOTF_Controller(void);
~AOTF_Controller(void);
AOTF_Controller::Error connect();
AOTF_Controller::Error disconnect();
AOTF_Controller::Error init();
AOTF_Controller::Error setFreq(float freq); // for frequency value in MHZ (precision to the 3rd decimal i.e. KHz)
AOTF_Controller::Error setFreq(long freq); // for frequency value in Hz
AOTF_Controller::Error setGain(int gain);
AOTF_Controller::Error reset();
AOTF_Controller::Error setScanningFreq(float _startFreq, float _endFreq, int numOfFrames);
AOTF_Controller::Error increaseFreq();
};
//Aotf_Controller.cpp
#include "StdAfx.h"
#include "AOTF_Controller.h"
AOTF_Controller::AOTF_Controller(void)
{
currentGain = 0;
currentFreq = 0;
startFreq = 0;
endFreq = 0;
deltaFreq = 0;
hAotfController = NULL;
}
AOTF_Controller::~AOTF_Controller(void)
{
}
AOTF_Controller::Error AOTF_Controller::connect()
{
int iInstance = 0;
hAotfController = AotfOpen(iInstance);
if (!hAotfController)
{
return CONNECTION_ERROR;
}
else
{
return SUCCESSFUL;
}
}
AOTF_Controller::Error AOTF_Controller::disconnect()
{
if (!AotfClose (hAotfController))
{
return DISCONNECTION_ERROR;
}
else
{
hAotfController = NULL;
return SUCCESSFUL;
}
}
AOTF_Controller::Error AOTF_Controller::init()
{
std::string ampCom="dds a 0 16383\r"; //Command to set the amplitude parameter to the max
std::string modCom="mod dac * 16383\r";//Command to set the dac parameter to the max
int gain = 255; // set the gain to the max
if (!AotfWrite(hAotfController, ampCom.length(), (char *)ampCom.c_str()))
{
return Error::INIT_ERROR;
}
if (!AotfWrite(hAotfController, modCom.length(), (char *)modCom.c_str()))
{
return INIT_ERROR;
}
setGain(gain);
return SUCCESSFUL;
}
AOTF_Controller::Error AOTF_Controller::reset()
{
std::string resetCom = "dds reset\r";
if(!AotfWrite(hAotfController, resetCom.length() , (char *)resetCom.c_str()))
{
return RESET_ERROR;
}
return SUCCESSFUL;
}
AOTF_Controller::Error AOTF_Controller::setFreq(float freq)
{
long freqHz = (long)freq*CONVERSION_MHZ_TO_HZ;
setFreq(freqHz);
return SUCCESSFUL;
}
AOTF_Controller::Error AOTF_Controller::setFreq(long freq)
{
std::ostringstream oss; //stream to build the string
//building the string for the Frequency
oss << "dds f 0 !" << std::fixed << std::setprecision(0) << freq << "\r";
std::string freqCom = oss.str();
//send command to the AOTF
if(!AotfWrite(hAotfController, freqCom.length(), (char *) freqCom.c_str())) // set the frequency (80-120)
{
return SET_ERROR;
}
currentFreq = freq; // update monitoring variable in HZ
return Error::SUCCESSFUL;
}
AOTF_Controller::Error AOTF_Controller::setGain(int gain)
{
std::ostringstream oss; //stream to build the string
//building the string for the Gain
oss << "dds gain -p* * " << gain << "\r";
std::string gainCom = oss.str();
//send command to the AOTF
if(!AotfWrite(hAotfController, gainCom.length(), (char * )gainCom.c_str())) // set the gain (0-255)
{
return SET_ERROR;
}
currentGain = gain;
return SUCCESSFUL;
}
AOTF_Controller::Error AOTF_Controller::setScanningFreq(float _startFreq, float _endFreq, int numOfFrames)
{
float FreqRange = (_endFreq - _startFreq); //calculate range
//calculate DeltaFrequency (frequency increase after each captured frame)
deltaFreq = (long) ((FreqRange/(float)(numOfFrames-1))*(float)CONVERSION_MHZ_TO_HZ); //conversion from MHz to Hz
startFreq = (long) (_startFreq*CONVERSION_MHZ_TO_HZ);
endFreq = (long) (_endFreq*CONVERSION_MHZ_TO_HZ);
setFreq(_startFreq);
return SUCCESSFUL;
}
AOTF_Controller::Error AOTF_Controller::increaseFreq()
{
if (deltaFreq ==0)
{
return SET_ERROR;
}
long newFreq = currentFreq + deltaFreq;
std::ostringstream oss;
oss << "dds f 0 !" << std::fixed << std::setprecision(0) << newFreq << "\r";
std::string freqCom = oss.str();
//send command to the AOTF
if(!AotfWrite(hAotfController, freqCom.length(), (char *)freqCom.c_str())) // set the frequency (80-120)value
{
return SET_ERROR;
}
currentFreq = newFreq;
return SUCCESSFUL;
}
Segmentation fault when retrieving OGRE 3D 1.81 submesh data.
I tried to make use of the code from http://alumni.cs.ucr.edu/~sorianom/cs134_09win/
to get ogre mesh data for Bullet physics engine to use, but encountered an error message that said Segment Fault.
After reducing the code to find the reason I found it's "submesh->indexData->indexStart" that caused segment fault.
I am running on Ubuntu Linux 12.10 ( 32bit x86)(Due the budget limit, we can not afford to buy Windows), and use g++ as compiler.
Please help me, I am an elementary school teacher who are trying to make some CAI programs for students to learn Math, English...
I know cs134 sample code listed on the site is a little bit too old, I've upgrade all the meshes, dotsceneloader... but still cannot figure out what have to change.
Thank you!
The following is the reduced code that still makes the segment fault error message.
#include <Ogre.h>
#include <ExampleApplication.h>
#include <btBulletCollisionCommon.h>
class SampleApp : public ExampleApplication
{
public:
// Basic constructor
SampleApp()
{}
protected:
// Just override the mandatory create scene method
void createScene(void) {
mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox");
Ogre::Light* myLight = mSceneMgr->createLight("Light0");
myLight->setType(Light::LT_POINT);
myLight->setPosition(0, 40, 0);
myLight->setDiffuseColour(1, 1, 1);
myLight->setSpecularColour(1, 1, 1);
Ogre::Entity* entity = mSceneMgr->createEntity("ogre", "ogrehead.mesh");
mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(entity);
Ogre::MeshPtr mesh = entity->getMesh();
Ogre::Mesh::SubMeshIterator j = mesh->getSubMeshIterator();
while (j.hasMoreElements()) {
Ogre::SubMesh* submesh = j.getNext();
std::cout << " submesh:" << submesh << "\n";
std::cout << " submesh->indexData:" << submesh->indexData << "\n";
//std::cout << " submesh->indexData->indexStart:" << submesh->indexData->indexStart << "\n";
int idxStart = submesh->indexData->indexStart;
int nIdx = submesh->indexData->indexCount;
}
}
};
// ----------------------------------------------------------------------------
// Main function, just boots the application object
// ----------------------------------------------------------------------------
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
int main(int argc, char **argv)
#endif
{
// Create application object
SampleApp app;
try
{
app.go();
}
catch( Exception& e )
{
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
std::cerr << "An exception has occured: " << e.getFullDescription();
#endif
}
return 0;
}
And the error message:
....
submesh:0xb752c080
submesh->indexData:0x8d042444
Segmentation fault (core dumped)
------------------
(program exited with code: 139)
The following is the gdb output:
(gdb) print submesh->indexData
$5 = (Ogre::IndexData *) 0x8d042444
(gdb) print submesh->indexData->indexStart
Cannot access memory at address 0x8d042458
(gdb)
ps: compiler setting: (You can compile the above code which is modified from CODE:BLOCK OGRE3D template , and bullet part isn't necessary in this reduced version)
g++ -o "%e" "%f" pkg-config --cflags --libs OGRE OIS bullet -I/usr/local/include/OGRE -I/usr/include/bullet
The original file is as following ( from http://tutorialsdl.googlecode.com/svn/trunk/Lab3/Lab3/OgreToBtMeshConverter.cpp) :
#include <Ogre.h>
#include <ExampleApplication.h>
#include <btBulletCollisionCommon.h>
class SampleApp : public ExampleApplication
{
public:
// Basic constructor
SampleApp()
{}
protected:
// Just override the mandatory create scene method
void createScene(void) {
mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox");
Ogre::Light* myLight = mSceneMgr->createLight("Light0");
myLight->setType(Light::LT_POINT);
myLight->setPosition(0, 40, 0);
myLight->setDiffuseColour(1, 1, 1);
myLight->setSpecularColour(1, 1, 1);
Ogre::Entity* entity = mSceneMgr->createEntity("ogre", "ninja.mesh");
mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(entity);
//
// initialize bullets collision detection system
//
btVector3 worldAabbMin(-1000,-1000,-1000);
btVector3 worldAabbMax(1000,1000,1000);
btDefaultCollisionConfiguration* mColConfig;
btCollisionWorld* mColWorld;
btCollisionDispatcher* mDispatcher;
btAxisSweep3* mBroadphase;
mBroadphase = new btAxisSweep3(worldAabbMin, worldAabbMax); // broadphase
mColConfig = new btDefaultCollisionConfiguration();
mDispatcher = new btCollisionDispatcher(mColConfig); // narrowphase pair-wise checking
mColWorld = new btCollisionWorld(mDispatcher, mBroadphase, mColConfig);
//
// Registers every mesh in OGREs scene manager with the
// collision world. You should be adding your environment
// to the scene manager before this call. Your moveable
// character should be created after this call as to avoid
// having his mesh become part of the static level geometry.
//
// All meshes here are placed into group 2 and set to
// collide with group 1. You character should be in group
// 1, and set to collide with group 2. More about contact groups
// in the manual.
btCollisionWorld* colWorld=0;
registerEntityAsCollider(entity,colWorld);
}
void registerEntityAsCollider(Entity* entity, btCollisionWorld* colWorld)
{
// if you wish to do instancing you will have to share one
// btTriangleMesh amongst multiple btBvhTriangleMeshShape
// instances
btTriangleMesh* btMesh = new btTriangleMesh();
MeshPtr mesh = entity->getMesh();
Mesh::SubMeshIterator j = mesh->getSubMeshIterator();
while (j.hasMoreElements()) {
SubMesh* submesh = j.getNext();
int idxStart = submesh->indexData->indexStart;
int nIdx = submesh->indexData->indexCount;
HardwareIndexBuffer* idxBuffer
= submesh->indexData->indexBuffer.get();
HardwareVertexBufferSharedPtr virtBuffer;
VertexDeclaration* virtDecl;
if (submesh->useSharedVertices) {
virtDecl = mesh->sharedVertexData->vertexDeclaration;
assert(mesh->sharedVertexData->vertexBufferBinding->getBufferCount() > 0);
virtBuffer = mesh->sharedVertexData->vertexBufferBinding->getBuffer(0);
} else {
virtDecl = submesh->vertexData->vertexDeclaration;
assert(submesh->vertexData->vertexBufferBinding->getBufferCount() > 0);
virtBuffer = submesh->vertexData->vertexBufferBinding->getBuffer(0);
}
unsigned char* pVert = static_cast<unsigned char*>(virtBuffer->lock(HardwareBuffer::HBL_READ_ONLY));
// need to lock the buffer since vertex data resides on GPU
// and we need synchronization
unsigned short* sindices = NULL;
unsigned long* lindices = NULL;
if (idxBuffer->getType() == HardwareIndexBuffer::IT_16BIT) {
sindices = static_cast<unsigned short*>(idxBuffer->lock(HardwareBuffer::HBL_READ_ONLY));
} else if (idxBuffer->getType() == HardwareIndexBuffer::IT_32BIT) {
lindices = static_cast<unsigned long*>(idxBuffer->lock(HardwareBuffer::HBL_READ_ONLY));
} else {
assert(true == false);
}
const VertexElement* elm = virtDecl->findElementBySemantic(VES_POSITION, 0);
int offset = elm->getOffset();
assert(elm->getType() == VET_FLOAT3);
for (int k = idxStart; k < idxStart + nIdx; k += 3) {
unsigned int indices[3];
btVector3 vertices[3];
if (idxBuffer->getType() == HardwareIndexBuffer::IT_16BIT) {
for (int l = 0; l < 3; ++l) {
indices[l] = sindices[k + l];
}
} else {
for (int l = 0; l < 3; ++l) {
indices[l] = lindices[k + l];
}
}
for (int l = 0; l < 3; ++l) { // for each vertex
Real* posVert = (Real*)(pVert + indices[l] * virtBuffer->getVertexSize() + offset);
for (int m = 0; m < 3; ++m) { // for each vertex component
vertices[l][m] = posVert[m];
}
}
btMesh->addTriangle(vertices[0], vertices[1], vertices[2]);
}
idxBuffer->unlock();
virtBuffer->unlock();
}
btBvhTriangleMeshShape* btMeshShape = new btBvhTriangleMeshShape(btMesh, true, true);
btCollisionObject* btObj = new btCollisionObject();
btObj->setCollisionShape(btMeshShape);
Vector3 pos = entity->getParentSceneNode()->getPosition();
Quaternion orient = entity->getParentSceneNode()->getOrientation();
Vector3 scale = entity->getParentSceneNode()->getScale();
btMeshShape->setLocalScaling(btVector3(scale[0], scale[1], scale[2]));
btMeshShape->setMargin(0.0);
btTransform btTrans;
btTrans.setIdentity();
btTrans.setOrigin(btVector3(pos[0], pos[1], pos[2]));
btTrans.setRotation(btQuaternion(orient[1], orient[2], orient[3], orient[0]));
btObj->setWorldTransform(btTrans);
// the last 2 parameters are bit strings representing group membership
// and the groups which it is allowed to collide with
colWorld->addCollisionObject(btObj, 2, 1);
}
//
// This method will take every entity in your scene and register it as
// a mesh in the btCollisionWorld. NOTE: Be sure to call this function after
// you've added your static entities (environment) to the scene manager but
// before you add your characters.
//
void registerAllEntitiesAsColliders(SceneManager* sceneMgr, btCollisionWorld* colWorld)
{
SceneManager::MovableObjectIterator
i = sceneMgr->getMovableObjectIterator("Entity");
while (i.hasMoreElements()) {
Entity* entity = static_cast<Entity*>(i.getNext());
registerEntityAsCollider(entity, colWorld);
}
}
};
// ----------------------------------------------------------------------------
// Main function, just boots the application object
// ----------------------------------------------------------------------------
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
int main(int argc, char **argv)
#endif
{
// Create application object
SampleApp app;
try
{
app.go();
}
catch( Exception& e )
{
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
std::cerr << "An exception has occured: " << e.getFullDescription();
#endif
}
return 0;
}