Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions src/platform/windows/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,18 @@ namespace platf::dxgi {
bool visible; ///< Whether the cursor is visible.
};

/**
* @brief Copy a mapped desktop texture into a RAM image in desktop orientation.
*
* Source and destination row padding are independent. Quarter turns exchange the source dimensions;
* the destination dimensions must already describe the rotated desktop.
*
* @param source Mapped texture containing the unrotated pixels.
* @param destination Allocated image in desktop coordinates.
* @param rotation Clockwise rotation from the source surface to the desktop image.
*/
void copy_mapped_image(const D3D11_MAPPED_SUBRESOURCE &source, ::platf::img_t &destination, DXGI_MODE_ROTATION rotation);

/**
* @brief GPU resources used to render a captured cursor shape.
*/
Expand Down Expand Up @@ -537,11 +549,11 @@ namespace platf::dxgi {
*/
int dummy_img(img_t *img) override;
/**
* @brief Finish cursor composition into a GPU-backed image.
* @brief Allocate a tightly packed RAM image in desktop orientation.
*
* @param img Image or frame object to read from or populate.
* @param dummy Unused placeholder required by the interface signature.
* @return Capture status after finalizing the captured image.
* @param dummy Whether to allow an unknown capture format for a fallback image.
* @return 0 on success, or -1 if a real frame's capture format is unknown.
*/
int complete_img(img_t *img, bool dummy) override;
/**
Expand Down
61 changes: 47 additions & 14 deletions src/platform/windows/display_ram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
* @file src/platform/windows/display_ram.cpp
* @brief Definitions for handling ram.
*/
// standard includes
#include <cstddef>

// local includes
#include "display.h"
#include "misc.h"
Expand All @@ -25,6 +28,39 @@ namespace platf::dxgi {
}
};

void copy_mapped_image(const D3D11_MAPPED_SUBRESOURCE &source, ::platf::img_t &destination, DXGI_MODE_ROTATION rotation) {
const auto source_data = static_cast<const std::uint8_t *>(source.pData);
const auto source_pitch = static_cast<std::ptrdiff_t>(source.RowPitch);
const auto pixel_pitch = destination.pixel_pitch;

for (int y = 0; y < destination.height; ++y) {
auto destination_row = destination.data + y * destination.row_pitch;
const std::uint8_t *source_row;
std::ptrdiff_t source_step;
switch (rotation) {
case DXGI_MODE_ROTATION_ROTATE90:
source_row = source_data + (destination.width - 1) * source_pitch + y * pixel_pitch;
source_step = -source_pitch;
break;
case DXGI_MODE_ROTATION_ROTATE180:
source_row = source_data + (destination.height - 1 - y) * source_pitch + (destination.width - 1) * pixel_pitch;
source_step = -pixel_pitch;
break;
case DXGI_MODE_ROTATION_ROTATE270:
source_row = source_data + (destination.height - 1 - y) * pixel_pitch;
source_step = source_pitch;
break;
default:
std::copy_n(source_data + y * source_pitch, destination.width * pixel_pitch, destination_row);
continue;
}

for (int x = 0; x < destination.width; ++x) {
std::copy_n(source_row + x * source_step, pixel_pitch, destination_row + x * pixel_pitch);
}
}
}

/**
* @brief Blend a monochrome cursor shape into a RAM frame.
*
Expand Down Expand Up @@ -270,8 +306,8 @@ namespace platf::dxgi {
BOOST_LOG(info) << "Capture format ["sv << dxgi_format_to_string(capture_format) << ']';

D3D11_TEXTURE2D_DESC t {};
t.Width = width;
t.Height = height;
t.Width = width_before_rotation;
t.Height = height_before_rotation;
t.MipLevels = 1;
t.ArraySize = 1;
t.SampleDesc.Count = 1;
Expand All @@ -289,8 +325,8 @@ namespace platf::dxgi {

// It's possible for our display enumeration to race with mode changes and result in
// mismatched image pool and desktop texture sizes. If this happens, just reinit again.
if (desc.Width != width || desc.Height != height) {
BOOST_LOG(info) << "Capture size changed ["sv << width << 'x' << height << " -> "sv << desc.Width << 'x' << desc.Height << ']';
if (desc.Width != width_before_rotation || desc.Height != height_before_rotation) {
BOOST_LOG(info) << "Capture size changed ["sv << width_before_rotation << 'x' << height_before_rotation << " -> "sv << desc.Width << 'x' << desc.Height << ']';
return capture_e::reinit;
}

Expand Down Expand Up @@ -334,7 +370,8 @@ namespace platf::dxgi {
return capture_e::capture_error;
}

std::copy_n((std::uint8_t *) img_info.pData, height * img_info.RowPitch, (std::uint8_t *) img->data);
// Rotate before cursor composition so both pixels and pointer use desktop coordinates.
copy_mapped_image(img_info, *img, display_rotation);

// Unmap the staging texture to allow GPU access again
device_ctx->Unmap(texture.get(), 0);
Expand Down Expand Up @@ -375,15 +412,11 @@ namespace platf::dxgi {

img->pixel_pitch = get_pixel_pitch();

if (dummy && !img->row_pitch) {
// Assume our dummy image will have no padding
img->row_pitch = img->pixel_pitch * img->width;
}

// Reallocate the image buffer if the pitch changes
if (!dummy && img->row_pitch != img_info.RowPitch) {
img->row_pitch = img_info.RowPitch;
delete img->data;
// The mapped texture may have different dimensions and padding before rotation.
const auto row_pitch = img->pixel_pitch * img->width;
if (img->row_pitch != row_pitch) {
img->row_pitch = row_pitch;
delete[] img->data;
img->data = nullptr;
}

Expand Down
3 changes: 2 additions & 1 deletion src/platform/windows/display_wgc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,8 @@ namespace platf::dxgi {
return capture_e::capture_error;
}

std::copy_n((std::uint8_t *) img_info.pData, height * img_info.RowPitch, (std::uint8_t *) img->data);
// WGC already supplies pixels in desktop orientation.
copy_mapped_image(img_info, *img, DXGI_MODE_ROTATION_IDENTITY);

// Unmap the staging texture to allow GPU access again
device_ctx->Unmap(texture.get(), 0);
Expand Down
Loading
Loading