mirror of https://github.com/AxioDL/boo.git
XAudio2 voices and D3D dynamic textures implemented
This commit is contained in:
parent
e1964f57a9
commit
1b3209f4bf
|
@ -28,7 +28,7 @@ void AudioMatrixMono::bufferMonoSampleData(IAudioVoice& voice, const int16_t* da
|
||||||
m_interleaveBuf.clear();
|
m_interleaveBuf.clear();
|
||||||
m_interleaveBuf.reserve(samples * chmap.m_channelCount);
|
m_interleaveBuf.reserve(samples * chmap.m_channelCount);
|
||||||
for (size_t s=0 ; s<samples ; ++s, ++data)
|
for (size_t s=0 ; s<samples ; ++s, ++data)
|
||||||
for (int c=0 ; c<chmap.m_channelCount ; ++c)
|
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
|
||||||
{
|
{
|
||||||
AudioChannel ch = chmap.m_channels[c];
|
AudioChannel ch = chmap.m_channels[c];
|
||||||
if (ch == AudioChannel::Unknown)
|
if (ch == AudioChannel::Unknown)
|
||||||
|
@ -64,7 +64,7 @@ void AudioMatrixStereo::bufferStereoSampleData(IAudioVoice& voice, const int16_t
|
||||||
m_interleaveBuf.clear();
|
m_interleaveBuf.clear();
|
||||||
m_interleaveBuf.reserve(frames * chmap.m_channelCount);
|
m_interleaveBuf.reserve(frames * chmap.m_channelCount);
|
||||||
for (size_t f=0 ; f<frames ; ++f, data += 2)
|
for (size_t f=0 ; f<frames ; ++f, data += 2)
|
||||||
for (int c=0 ; c<chmap.m_channelCount ; ++c)
|
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
|
||||||
{
|
{
|
||||||
AudioChannel ch = chmap.m_channels[c];
|
AudioChannel ch = chmap.m_channels[c];
|
||||||
if (ch == AudioChannel::Unknown)
|
if (ch == AudioChannel::Unknown)
|
||||||
|
|
|
@ -14,7 +14,7 @@ struct XA2AudioVoice : IAudioVoice
|
||||||
IAudioVoiceCallback* m_cb;
|
IAudioVoiceCallback* m_cb;
|
||||||
IXAudio2SourceVoice* m_voiceQueue;
|
IXAudio2SourceVoice* m_voiceQueue;
|
||||||
XAUDIO2_BUFFER m_buffers[3] = {};
|
XAUDIO2_BUFFER m_buffers[3] = {};
|
||||||
size_t m_bufferFrames = 2048;
|
size_t m_bufferFrames = 1024;
|
||||||
size_t m_frameSize;
|
size_t m_frameSize;
|
||||||
|
|
||||||
const ChannelMap& channelMap() const {return m_map;}
|
const ChannelMap& channelMap() const {return m_map;}
|
||||||
|
@ -27,7 +27,7 @@ struct XA2AudioVoice : IAudioVoice
|
||||||
|
|
||||||
STDMETHOD_(void, OnBufferEnd)(void* pBufferContext)
|
STDMETHOD_(void, OnBufferEnd)(void* pBufferContext)
|
||||||
{
|
{
|
||||||
m_voice.m_cb->needsNextBuffer(&m_voice, m_voice.m_bufferFrames);
|
m_voice.m_cb->needsNextBuffer(m_voice, m_voice.m_bufferFrames);
|
||||||
}
|
}
|
||||||
STDMETHOD_(void, OnBufferStart)(void* pBufferContext) {}
|
STDMETHOD_(void, OnBufferStart)(void* pBufferContext) {}
|
||||||
STDMETHOD_(void, OnLoopEnd)(void* pBufferContext) {}
|
STDMETHOD_(void, OnLoopEnd)(void* pBufferContext) {}
|
||||||
|
@ -48,11 +48,12 @@ struct XA2AudioVoice : IAudioVoice
|
||||||
desc.nSamplesPerSec = sampleRate;
|
desc.nSamplesPerSec = sampleRate;
|
||||||
desc.wBitsPerSample = 16;
|
desc.wBitsPerSample = 16;
|
||||||
desc.nBlockAlign = desc.nChannels * desc.wBitsPerSample / 8;
|
desc.nBlockAlign = desc.nChannels * desc.wBitsPerSample / 8;
|
||||||
desc.nAvgBytesPerSec = desc.nAvgBytesPerSec * desc.nBlockAlign;
|
desc.nAvgBytesPerSec = desc.nSamplesPerSec * desc.nBlockAlign;
|
||||||
|
|
||||||
if FAILED(xa2.CreateSourceVoice(&m_voiceQueue, &desc, 0, XAUDIO2_DEFAULT_FREQ_RATIO, &m_xaCb))
|
HRESULT err = xa2.CreateSourceVoice(&m_voiceQueue, &desc, 0, XAUDIO2_DEFAULT_FREQ_RATIO, &m_xaCb);
|
||||||
|
if (FAILED(err))
|
||||||
{
|
{
|
||||||
Log.report(logvisor::Error, "unable to create source voice");
|
Log.report(logvisor::Fatal, "unable to create source voice");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +115,7 @@ struct XA2AudioVoice : IAudioVoice
|
||||||
m_frameSize = chCount * 2;
|
m_frameSize = chCount * 2;
|
||||||
|
|
||||||
for (unsigned i=0 ; i<3 ; ++i)
|
for (unsigned i=0 ; i<3 ; ++i)
|
||||||
m_cb->needsNextBuffer(this, m_bufferFrames);
|
m_cb->needsNextBuffer(*this, m_bufferFrames);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bufferSampleData(const int16_t* data, size_t frames)
|
void bufferSampleData(const int16_t* data, size_t frames)
|
||||||
|
@ -122,8 +123,15 @@ struct XA2AudioVoice : IAudioVoice
|
||||||
XAUDIO2_BUFFER* buf = &m_buffers[m_fillBuf++];
|
XAUDIO2_BUFFER* buf = &m_buffers[m_fillBuf++];
|
||||||
if (m_fillBuf == 3)
|
if (m_fillBuf == 3)
|
||||||
m_fillBuf = 0;
|
m_fillBuf = 0;
|
||||||
|
buf->Flags = 0;
|
||||||
buf->AudioBytes = frames * m_frameSize;
|
buf->AudioBytes = frames * m_frameSize;
|
||||||
buf->pAudioData = reinterpret_cast<const BYTE*>(data);
|
buf->pAudioData = reinterpret_cast<const BYTE*>(data);
|
||||||
|
buf->PlayBegin = 0;
|
||||||
|
buf->PlayLength = 0;
|
||||||
|
buf->LoopBegin = 0;
|
||||||
|
buf->LoopLength = 0;
|
||||||
|
buf->LoopCount = 0;
|
||||||
|
buf->pContext = nullptr;
|
||||||
m_voiceQueue->SubmitSourceBuffer(buf);
|
m_voiceQueue->SubmitSourceBuffer(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,28 +151,43 @@ struct XA2AudioVoice : IAudioVoice
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef HRESULT (__stdcall *PFN_XAudio2Create)(_Outptr_ IXAudio2** ppXAudio2, UINT32 Flags,
|
||||||
|
XAUDIO2_PROCESSOR XAudio2Processor);
|
||||||
|
|
||||||
|
static PFN_XAudio2Create MyXAudio2Create = nullptr;
|
||||||
|
|
||||||
struct XA2AudioVoiceAllocator : IAudioVoiceAllocator
|
struct XA2AudioVoiceAllocator : IAudioVoiceAllocator
|
||||||
{
|
{
|
||||||
ComPtr<IXAudio2> m_xa2;
|
ComPtr<IXAudio2> m_xa2;
|
||||||
IXAudio2MasteringVoice* m_masterVoice;
|
IXAudio2MasteringVoice* m_masterVoice;
|
||||||
AudioChannelSet m_maxSet;
|
AudioChannelSet m_maxSet = AudioChannelSet::Unknown;
|
||||||
|
|
||||||
XA2AudioVoiceAllocator()
|
XA2AudioVoiceAllocator()
|
||||||
{
|
{
|
||||||
if (FAILED(XAudio2Create(&m_xa2)))
|
if (!MyXAudio2Create)
|
||||||
{
|
{
|
||||||
Log.report(logvisor::Error, "Unable to initialize XAudio2");
|
HMODULE mod = LoadLibraryW(XAUDIO2_DLL_W);
|
||||||
|
if (!mod)
|
||||||
|
Log.report(logvisor::Fatal, L"unable to load " XAUDIO2_DLL_W);
|
||||||
|
MyXAudio2Create = PFN_XAudio2Create(GetProcAddress(mod, "XAudio2Create"));
|
||||||
|
if (!MyXAudio2Create)
|
||||||
|
Log.report(logvisor::Fatal, L"unable to find XAudio2Create in " XAUDIO2_DLL_W);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FAILED(MyXAudio2Create(&m_xa2, 0, XAUDIO2_DEFAULT_PROCESSOR)))
|
||||||
|
{
|
||||||
|
Log.report(logvisor::Fatal, "Unable to initialize XAudio2");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (FAILED(m_xa2->CreateMasteringVoice(&m_masterVoice)))
|
if (FAILED(m_xa2->CreateMasteringVoice(&m_masterVoice)))
|
||||||
{
|
{
|
||||||
Log.report(logvisor::Error, "Unable to initialize XAudio2 mastering voice");
|
Log.report(logvisor::Fatal, "Unable to initialize XAudio2 mastering voice");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DWORD channelMask;
|
DWORD channelMask;
|
||||||
if (FAILED(m_masterVoice->GetChannelMask(&channelMask)))
|
if (FAILED(m_masterVoice->GetChannelMask(&channelMask)))
|
||||||
{
|
{
|
||||||
Log.report(logvisor::Error, "Unable to get mastering voice's channel mask");
|
Log.report(logvisor::Fatal, "Unable to get mastering voice's channel mask");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((channelMask & (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)) == (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT))
|
if ((channelMask & (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)) == (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT))
|
||||||
|
@ -190,17 +213,24 @@ struct XA2AudioVoiceAllocator : IAudioVoiceAllocator
|
||||||
m_masterVoice->DestroyVoice();
|
m_masterVoice->DestroyVoice();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AudioChannelSet getAvailableSet()
|
||||||
|
{
|
||||||
|
return m_maxSet;
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<IAudioVoice> allocateNewVoice(AudioChannelSet layoutOut,
|
std::unique_ptr<IAudioVoice> allocateNewVoice(AudioChannelSet layoutOut,
|
||||||
unsigned sampleRate,
|
unsigned sampleRate,
|
||||||
IAudioVoiceCallback* cb)
|
IAudioVoiceCallback* cb)
|
||||||
{
|
{
|
||||||
AudioChannelSet acset = std::min(layoutOut, m_maxSet);
|
AudioChannelSet acset = std::min(layoutOut, m_maxSet);
|
||||||
XA2AudioVoice* newVoice = new XA2AudioVoice(*m_xa2.Get(), acset, sampleRate, cb);
|
std::unique_ptr<IAudioVoice> newVoice = std::make_unique<XA2AudioVoice>
|
||||||
std::unique_ptr<IAudioVoice> ret(newVoice);
|
(*m_xa2.Get(), acset, sampleRate, cb);
|
||||||
if (!newVoice->m_voiceQueue)
|
if (!static_cast<XA2AudioVoice*>(newVoice.get())->m_voiceQueue)
|
||||||
return {};
|
return {};
|
||||||
return ret;
|
return newVoice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pumpVoices() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<IAudioVoiceAllocator> NewAudioVoiceAllocator()
|
std::unique_ptr<IAudioVoiceAllocator> NewAudioVoiceAllocator()
|
||||||
|
|
|
@ -264,7 +264,7 @@ class D3D11TextureD : public ITextureD
|
||||||
m_cpuBuf.reset(new uint8_t[m_cpuSz]);
|
m_cpuBuf.reset(new uint8_t[m_cpuSz]);
|
||||||
|
|
||||||
CD3D11_TEXTURE2D_DESC desc(pixelFmt, width, height, 1, 1,
|
CD3D11_TEXTURE2D_DESC desc(pixelFmt, width, height, 1, 1,
|
||||||
D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_DEFAULT, D3D11_CPU_ACCESS_WRITE);
|
D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
|
||||||
for (int i=0 ; i<3 ; ++i)
|
for (int i=0 ; i<3 ; ++i)
|
||||||
{
|
{
|
||||||
ThrowIfFailed(ctx->m_dev->CreateTexture2D(&desc, nullptr, &m_texs[i]));
|
ThrowIfFailed(ctx->m_dev->CreateTexture2D(&desc, nullptr, &m_texs[i]));
|
||||||
|
|
|
@ -338,24 +338,32 @@ class D3D12TextureD : public ITextureD
|
||||||
D3D12CommandQueue* m_q;
|
D3D12CommandQueue* m_q;
|
||||||
D3D12_RESOURCE_DESC m_gpuDesc;
|
D3D12_RESOURCE_DESC m_gpuDesc;
|
||||||
std::unique_ptr<uint8_t[]> m_cpuBuf;
|
std::unique_ptr<uint8_t[]> m_cpuBuf;
|
||||||
|
size_t m_rowPitch;
|
||||||
size_t m_cpuSz;
|
size_t m_cpuSz;
|
||||||
int m_validSlots = 0;
|
int m_validSlots = 0;
|
||||||
D3D12TextureD(D3D12CommandQueue* q, D3D12Context* ctx, size_t width, size_t height, TextureFormat fmt)
|
D3D12TextureD(D3D12CommandQueue* q, D3D12Context* ctx, size_t width, size_t height, TextureFormat fmt)
|
||||||
: m_fmt(fmt), m_q(q)
|
: m_width(width), m_height(height), m_fmt(fmt), m_q(q)
|
||||||
{
|
{
|
||||||
DXGI_FORMAT pixelFmt;
|
DXGI_FORMAT pixelFmt;
|
||||||
|
size_t pxPitch;
|
||||||
switch (fmt)
|
switch (fmt)
|
||||||
{
|
{
|
||||||
case TextureFormat::RGBA8:
|
case TextureFormat::RGBA8:
|
||||||
pixelFmt = DXGI_FORMAT_R8G8B8A8_UNORM;
|
pixelFmt = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
pxPitch = 4;
|
||||||
break;
|
break;
|
||||||
case TextureFormat::I8:
|
case TextureFormat::I8:
|
||||||
pixelFmt = DXGI_FORMAT_R8_UNORM;
|
pixelFmt = DXGI_FORMAT_R8_UNORM;
|
||||||
|
pxPitch = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Log.report(logvisor::Fatal, "unsupported tex format");
|
Log.report(logvisor::Fatal, "unsupported tex format");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_cpuSz = width * height * pxPitch;
|
||||||
|
m_rowPitch = width * pxPitch;
|
||||||
|
m_cpuBuf.reset(new uint8_t[m_cpuSz]);
|
||||||
|
|
||||||
m_gpuDesc = CD3DX12_RESOURCE_DESC::Tex2D(pixelFmt, width, height);
|
m_gpuDesc = CD3DX12_RESOURCE_DESC::Tex2D(pixelFmt, width, height);
|
||||||
size_t reqSz = GetRequiredIntermediateSize(ctx->m_dev.Get(), &m_gpuDesc, 0, 1);
|
size_t reqSz = GetRequiredIntermediateSize(ctx->m_dev.Get(), &m_gpuDesc, 0, 1);
|
||||||
for (int i=0 ; i<2 ; ++i)
|
for (int i=0 ; i<2 ; ++i)
|
||||||
|
@ -1389,13 +1397,21 @@ void D3D12TextureD::update(int b)
|
||||||
m_q->stallDynamicUpload();
|
m_q->stallDynamicUpload();
|
||||||
ID3D12Resource* res = m_texs[b].Get();
|
ID3D12Resource* res = m_texs[b].Get();
|
||||||
ID3D12Resource* gpuRes = m_gpuTexs[b].Get();
|
ID3D12Resource* gpuRes = m_gpuTexs[b].Get();
|
||||||
D3D12_SUBRESOURCE_DATA d = {m_cpuBuf.get(), LONG_PTR(m_width * 4), LONG_PTR(m_cpuSz)};
|
D3D12_SUBRESOURCE_DATA d = {m_cpuBuf.get(), LONG_PTR(m_rowPitch), LONG_PTR(m_cpuSz)};
|
||||||
m_q->m_dynamicCmdList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(gpuRes,
|
D3D12_RESOURCE_BARRIER setupCopy[] =
|
||||||
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_COPY_DEST));
|
{
|
||||||
|
CD3DX12_RESOURCE_BARRIER::Transition(gpuRes,
|
||||||
|
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_COPY_DEST),
|
||||||
|
};
|
||||||
|
m_q->m_dynamicCmdList->ResourceBarrier(1, setupCopy);
|
||||||
if (!UpdateSubresources<1>(m_q->m_dynamicCmdList.Get(), gpuRes, res, 0, 0, 1, &d))
|
if (!UpdateSubresources<1>(m_q->m_dynamicCmdList.Get(), gpuRes, res, 0, 0, 1, &d))
|
||||||
Log.report(logvisor::Fatal, "unable to update dynamic texture data");
|
Log.report(logvisor::Fatal, "unable to update dynamic texture data");
|
||||||
m_q->m_dynamicCmdList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(gpuRes,
|
D3D12_RESOURCE_BARRIER teardownCopy[] =
|
||||||
D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE));
|
{
|
||||||
|
CD3DX12_RESOURCE_BARRIER::Transition(gpuRes,
|
||||||
|
D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE),
|
||||||
|
};
|
||||||
|
m_q->m_dynamicCmdList->ResourceBarrier(1, teardownCopy);
|
||||||
m_validSlots |= slot;
|
m_validSlots |= slot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -285,6 +285,7 @@ public:
|
||||||
int clientReturn = 0;
|
int clientReturn = 0;
|
||||||
std::thread clientThread([&]()
|
std::thread clientThread([&]()
|
||||||
{
|
{
|
||||||
|
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
||||||
clientReturn = m_callback.appMain(this);
|
clientReturn = m_callback.appMain(this);
|
||||||
PostThreadMessage(g_mainThreadId, WM_USER+1, 0, 0);
|
PostThreadMessage(g_mainThreadId, WM_USER+1, 0, 0);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue