Skip to content

Commit

Permalink
Added scanline protocol analyzer display. Fixes #619.
Browse files Browse the repository at this point in the history
  • Loading branch information
azonenberg committed Nov 21, 2024
1 parent f207d18 commit c71bc9f
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 5 deletions.
2 changes: 1 addition & 1 deletion lib
4 changes: 4 additions & 0 deletions src/ngscopeclient/PacketManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

#include "../../lib/scopehal/PacketDecoder.h"
#include "Marker.h"
#include "TextureManager.h"

class Session;

Expand Down Expand Up @@ -84,6 +85,9 @@ class RowData

///@brief The marker in this row (ignored if m_packet is valid)
Marker m_marker;

///@brief Texture containing the scanline image for this row (only valid if m_packet is a VideoScanlinePacket)
std::shared_ptr<Texture> m_texture;
};

class ProtocolDisplayFilter;
Expand Down
104 changes: 101 additions & 3 deletions src/ngscopeclient/ProtocolAnalyzerDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "ngscopeclient.h"
#include "ProtocolAnalyzerDialog.h"
#include "MainWindow.h"
#include "../../lib/scopeprotocols/RGBLEDDecoder.h"

using namespace std;

Expand Down Expand Up @@ -362,7 +363,7 @@ bool ProtocolAnalyzerDialog::DoRender()
if(firstRow)
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - (ImGui::GetScrollY() - rowStart));

DoImageColumn(pack);
DoImageColumn(pack, rows, i);
}
}

Expand Down Expand Up @@ -451,9 +452,106 @@ bool ProtocolAnalyzerDialog::DoRender()
/**
@brief Handles the "image" column for packets
*/
void ProtocolAnalyzerDialog::DoImageColumn(Packet* pack)
void ProtocolAnalyzerDialog::DoImageColumn(Packet* pack, vector<RowData>& rows, size_t nrow)
{
ImGui::TextUnformatted("Image TODO");
//TODO: get the actual texture
auto pos = ImGui::GetCursorScreenPos();
auto list = ImGui::GetWindowDrawList();
auto size = ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetTextLineHeight());

//auto tex = m_parent.GetTextureManager()->GetTexture("visible-spectrum-380nm-750nm");

if(!rows[nrow].m_texture)
{
size_t width = pack->m_data.size() / 3;

LogTrace("filling texture with 1x%zu pixels of scanline data\n", width);
LogIndenter li;

//TODO: this and TextureManager::LoadTexture have a lot in common
//we should refactor into common code
VkDeviceSize devsize = width * 4;

//Allocate temporary staging buffer
vk::BufferCreateInfo bufinfo({}, devsize, vk::BufferUsageFlagBits::eTransferSrc);
vk::raii::Buffer stagingBuf(*g_vkComputeDevice, bufinfo);

//Figure out memory requirements of the buffer and decide what physical memory type to use
//For now, default to using the first type in the mask that is host visible
auto req = stagingBuf.getMemoryRequirements();
auto memProperties = g_vkComputePhysicalDevice->getMemoryProperties();
uint32_t memType = 0;
for(uint32_t i=0; i<32; i++)
{
//Skip anything not host visible since we have to be able to write to it
if(!(memProperties.memoryTypes[i].propertyFlags & vk::MemoryPropertyFlagBits::eHostVisible))
continue;

//Stop if buffer is compatible
if(req.memoryTypeBits & (1 << i) )
{
memType = i;
break;
}
}
LogTrace("Using memory type %u for staging buffer\n", memType);

//Allocate the memory and bind to the buffer
vk::MemoryAllocateInfo minfo(req.size, memType);
vk::raii::DeviceMemory physMem(*g_vkComputeDevice, minfo);
auto mappedPtr = reinterpret_cast<uint8_t*>(physMem.mapMemory(0, req.size));
stagingBuf.bindMemory(*physMem, 0);

//Special case: RGB LED decodes can have scaling if not running at full brightness
float scale = 1;
auto rgbf = dynamic_cast<RGBLEDDecoder*>(m_filter);
if(rgbf)
scale = rgbf->GetScale();

//Fill the mapped buffer with image data
for(size_t i=0; i<width; i++)
{
mappedPtr[i*4] = min(pack->m_data[i*3] * scale, 255.0f);
mappedPtr[i*4 + 1] = min(pack->m_data[i*3 + 1] * scale, 255.0f);
mappedPtr[i*4 + 2] = min(pack->m_data[i*3 + 2] * scale, 255.0f);
mappedPtr[i*4 + 3] = 255;
}
physMem.unmapMemory();

//NOTE: Assumes the render queue is also capable of transfers (see QueueManager)
vk::ImageCreateInfo imageInfo(
{},
vk::ImageType::e2D,
vk::Format::eR8G8B8A8Unorm,
vk::Extent3D(width, 1, 1),
1,
1,
VULKAN_HPP_NAMESPACE::SampleCountFlagBits::e1,
VULKAN_HPP_NAMESPACE::ImageTiling::eOptimal,
vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled,
vk::SharingMode::eExclusive,
{},
vk::ImageLayout::eUndefined
);

//Make the Vulkan texture for it
rows[nrow].m_texture = make_shared<Texture>(
*g_vkComputeDevice,
imageInfo,
stagingBuf,
width,
1,
m_parent.GetTextureManager(),
"ProtocolAnalyzerDialog.scanline",
false);
}

//Actually draw it
auto tex = rows[nrow].m_texture;
list->AddImage(
tex->GetTexture(),
pos,
pos + size);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/ngscopeclient/ProtocolAnalyzerDialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class ProtocolAnalyzerDialog : public Dialog
bool m_needToScrollToSelectedPacket;

void DoDataColumn(Packet* pack, ImFont* dataFont, std::vector<RowData>& rows, size_t nrow);
void DoImageColumn(Packet* pack);
void DoImageColumn(Packet* pack, std::vector<RowData>& rows, size_t nrow);

///@brief True the first time DoDataColumn() is called in a given frame
bool m_firstDataBlockOfFrame;
Expand Down

0 comments on commit c71bc9f

Please sign in to comment.