Plumb QuicStreamPriority through QuicStream and QuicSession.

No functional change still: the RFC9218 urgency has the same range as SPDY
priorities (0 to 7 inclusive), so they can be used interchangeably, and RFC9218
incremental bit is always set to false in production.

Note that this CL adds the capability to send PRIORITY_UPDATE frames with
incremental bit set to true.  This is not used in production, and in practice
the server does not send PRIORITY_UPDATE frames anyway.  However, this CL
will allow Chrome to send such frames.

This CL does not touch methods used for Google QUIC HEADERS and PRIORITY frames
on the headers stream, because they use SpdyStreamPrecedence directly.  These
calls will eventually be removed with gQUIC.

QuicWriteBlockedList changes will follow in a separate CL.

https://github.com/google/quiche/issues/25

PiperOrigin-RevId: 494791164
diff --git a/quiche/quic/core/http/quic_receive_control_stream.cc b/quiche/quic/core/http/quic_receive_control_stream.cc
index b2b56d8..87e9bd7 100644
--- a/quiche/quic/core/http/quic_receive_control_stream.cc
+++ b/quiche/quic/core/http/quic_receive_control_stream.cc
@@ -149,8 +149,8 @@
     }
 
     const QuicStreamId stream_id = frame.prioritized_element_id;
-    return spdy_session_->OnPriorityUpdateForRequestStream(
-        stream_id, result.priority.urgency);
+    return spdy_session_->OnPriorityUpdateForRequestStream(stream_id,
+                                                           result.priority);
   }
 
   for (absl::string_view key_value :
@@ -179,7 +179,9 @@
     }
 
     return spdy_session_->OnPriorityUpdateForRequestStream(
-        frame.prioritized_element_id, urgency);
+        frame.prioritized_element_id,
+        QuicStreamPriority{static_cast<uint8_t>(urgency),
+                           QuicStreamPriority::kDefaultIncremental});
   }
 
   // Ignore frame if no urgency parameter can be parsed.
diff --git a/quiche/quic/core/http/quic_server_session_base_test.cc b/quiche/quic/core/http/quic_server_session_base_test.cc
index a722240..133dcbf 100644
--- a/quiche/quic/core/http/quic_server_session_base_test.cc
+++ b/quiche/quic/core/http/quic_server_session_base_test.cc
@@ -546,8 +546,7 @@
   if (!VersionUsesHttp3(transport_version())) {
     session_->RegisterStreamPriority(
         QuicUtils::GetHeadersStreamId(transport_version()),
-        /*is_static=*/true,
-        spdy::SpdyStreamPrecedence(QuicStream::kDefaultPriority));
+        /*is_static=*/true, QuicStreamPriority());
   }
 
   // Set some initial bandwidth values.
diff --git a/quiche/quic/core/http/quic_spdy_session.cc b/quiche/quic/core/http/quic_spdy_session.cc
index ae83de6..c404b70 100644
--- a/quiche/quic/core/http/quic_spdy_session.cc
+++ b/quiche/quic/core/http/quic_spdy_session.cc
@@ -620,8 +620,8 @@
   stream->OnPriorityFrame(precedence);
 }
 
-bool QuicSpdySession::OnPriorityUpdateForRequestStream(QuicStreamId stream_id,
-                                                       int urgency) {
+bool QuicSpdySession::OnPriorityUpdateForRequestStream(
+    QuicStreamId stream_id, QuicStreamPriority priority) {
   if (perspective() == Perspective::IS_CLIENT ||
       !QuicUtils::IsBidirectionalStreamId(stream_id, version()) ||
       !QuicUtils::IsClientInitiatedStreamId(transport_version(), stream_id)) {
@@ -642,7 +642,7 @@
     return false;
   }
 
-  if (MaybeSetStreamPriority(stream_id, spdy::SpdyStreamPrecedence(urgency))) {
+  if (MaybeSetStreamPriority(stream_id, priority)) {
     return true;
   }
 
@@ -650,7 +650,7 @@
     return true;
   }
 
-  buffered_stream_priorities_[stream_id] = urgency;
+  buffered_stream_priorities_[stream_id] = priority;
 
   if (buffered_stream_priorities_.size() >
       10 * max_open_incoming_bidirectional_streams()) {
@@ -842,7 +842,7 @@
     return;
   }
 
-  stream->SetPriority(spdy::SpdyStreamPrecedence(it->second));
+  stream->SetPriority(it->second);
   buffered_stream_priorities_.erase(it);
 }
 
diff --git a/quiche/quic/core/http/quic_spdy_session.h b/quiche/quic/core/http/quic_spdy_session.h
index 60ff11a..97451e5 100644
--- a/quiche/quic/core/http/quic_spdy_session.h
+++ b/quiche/quic/core/http/quic_spdy_session.h
@@ -181,7 +181,8 @@
 
   // Called when an HTTP/3 PRIORITY_UPDATE frame has been received for a request
   // stream.  Returns false and closes connection if |stream_id| is invalid.
-  bool OnPriorityUpdateForRequestStream(QuicStreamId stream_id, int urgency);
+  bool OnPriorityUpdateForRequestStream(QuicStreamId stream_id,
+                                        QuicStreamPriority priority);
 
   // Called when an HTTP/3 ACCEPT_CH frame has been received.
   // This method will only be called for client sessions.
@@ -623,7 +624,8 @@
 
   // Priority values received in PRIORITY_UPDATE frames for streams that are not
   // open yet.
-  absl::flat_hash_map<QuicStreamId, int> buffered_stream_priorities_;
+  absl::flat_hash_map<QuicStreamId, QuicStreamPriority>
+      buffered_stream_priorities_;
 
   // An integer used for live check. The indicator is assigned a value in
   // constructor. As long as it is not the assigned value, that would indicate
diff --git a/quiche/quic/core/http/quic_spdy_session_test.cc b/quiche/quic/core/http/quic_spdy_session_test.cc
index 7410728..209b4f8 100644
--- a/quiche/quic/core/http/quic_spdy_session_test.cc
+++ b/quiche/quic/core/http/quic_spdy_session_test.cc
@@ -898,7 +898,8 @@
   // Now let stream 4 do the 2nd of its 3 writes, but add a block for a high
   // priority stream 6.  4 should be preempted.  6 will write but *not* block so
   // will cede back to 4.
-  stream6->SetPriority(spdy::SpdyStreamPrecedence(kV3HighestPriority));
+  stream6->SetPriority(QuicStreamPriority{
+      kV3HighestPriority, QuicStreamPriority::kDefaultIncremental});
   EXPECT_CALL(*stream4, OnCanWrite())
       .WillOnce(Invoke([this, stream4, stream6]() {
         session_.SendLargeFakeData(stream4, 6000);
@@ -2175,8 +2176,10 @@
   TestStream* stream = session_.CreateIncomingStream(stream_id);
   session_.OnPriorityFrame(stream_id,
                            spdy::SpdyStreamPrecedence(kV3HighestPriority));
-  EXPECT_EQ(spdy::SpdyStreamPrecedence(kV3HighestPriority),
-            stream->precedence());
+
+  EXPECT_EQ((QuicStreamPriority{kV3HighestPriority,
+                                QuicStreamPriority::kDefaultIncremental}),
+            stream->priority());
 }
 
 TEST_P(QuicSpdySessionTestServer, OnPriorityUpdateFrame) {
@@ -2220,11 +2223,13 @@
 
   // PRIORITY_UPDATE frame arrives after stream creation.
   TestStream* stream1 = session_.CreateIncomingStream(stream_id1);
-  EXPECT_EQ(QuicStreamPriority::kDefaultUrgency,
-            stream1->precedence().spdy3_priority());
+  EXPECT_EQ((QuicStreamPriority{QuicStreamPriority::kDefaultUrgency,
+                                QuicStreamPriority::kDefaultIncremental}),
+            stream1->priority());
   EXPECT_CALL(debug_visitor, OnPriorityUpdateFrameReceived(priority_update1));
   session_.OnStreamFrame(data3);
-  EXPECT_EQ(2u, stream1->precedence().spdy3_priority());
+  EXPECT_EQ((QuicStreamPriority{2u, QuicStreamPriority::kDefaultIncremental}),
+            stream1->priority());
 
   // PRIORITY_UPDATE frame for second request stream.
   const QuicStreamId stream_id2 = GetNthClientInitiatedBidirectionalId(1);
@@ -2241,7 +2246,8 @@
   session_.OnStreamFrame(stream_frame3);
   // Priority is applied upon stream construction.
   TestStream* stream2 = session_.CreateIncomingStream(stream_id2);
-  EXPECT_EQ(2u, stream2->precedence().spdy3_priority());
+  EXPECT_EQ((QuicStreamPriority{2u, QuicStreamPriority::kDefaultIncremental}),
+            stream2->priority());
 }
 
 TEST_P(QuicSpdySessionTestServer, OnInvalidPriorityUpdateFrame) {
diff --git a/quiche/quic/core/http/quic_spdy_stream.cc b/quiche/quic/core/http/quic_spdy_stream.cc
index 4cb89a8..aded5c8 100644
--- a/quiche/quic/core/http/quic_spdy_stream.cc
+++ b/quiche/quic/core/http/quic_spdy_stream.cc
@@ -37,7 +37,6 @@
 #include "quiche/spdy/core/spdy_protocol.h"
 
 using spdy::Http2HeaderBlock;
-using spdy::SpdyPriority;
 
 namespace quic {
 
@@ -503,7 +502,8 @@
     const spdy::SpdyStreamPrecedence& precedence) {
   QUICHE_DCHECK_EQ(Perspective::IS_SERVER,
                    session()->connection()->perspective());
-  SetPriority(precedence);
+  SetPriority(QuicStreamPriority{precedence.spdy3_priority(),
+                                 QuicStreamPriority::kDefaultIncremental});
 }
 
 void QuicSpdyStream::OnStreamHeaderList(bool fin, size_t frame_len,
@@ -585,16 +585,12 @@
     return;
   }
 
-  // Value between 0 and 7, inclusive.  Lower value means higher priority.
-  const uint8_t urgency = precedence().spdy3_priority();
-  const QuicStreamPriority priority{urgency,
-                                    QuicStreamPriority::kDefaultIncremental};
-  if (last_sent_priority_ == priority) {
+  if (last_sent_priority_ == priority()) {
     return;
   }
-  last_sent_priority_ = priority;
+  last_sent_priority_ = priority();
 
-  spdy_session_->WriteHttp3PriorityUpdate(id(), priority);
+  spdy_session_->WriteHttp3PriorityUpdate(id(), priority());
 }
 
 void QuicSpdyStream::OnHeadersTooLarge() { Reset(QUIC_HEADERS_TOO_LARGE); }
@@ -706,7 +702,8 @@
     const spdy::SpdyStreamPrecedence& precedence) {
   QUICHE_DCHECK_EQ(Perspective::IS_SERVER,
                    session()->connection()->perspective());
-  SetPriority(precedence);
+  SetPriority(QuicStreamPriority{precedence.spdy3_priority(),
+                                 QuicStreamPriority::kDefaultIncremental});
 }
 
 void QuicSpdyStream::OnStreamReset(const QuicRstStreamFrame& frame) {
@@ -1151,7 +1148,8 @@
         ack_listener) {
   if (!VersionUsesHttp3(transport_version())) {
     return spdy_session_->WriteHeadersOnHeadersStream(
-        id(), std::move(header_block), fin, precedence(),
+        id(), std::move(header_block), fin,
+        spdy::SpdyStreamPrecedence(priority().urgency),
         std::move(ack_listener));
   }
 
diff --git a/quiche/quic/core/http/quic_spdy_stream_test.cc b/quiche/quic/core/http/quic_spdy_stream_test.cc
index a147e93..0325538 100644
--- a/quiche/quic/core/http/quic_spdy_stream_test.cc
+++ b/quiche/quic/core/http/quic_spdy_stream_test.cc
@@ -44,7 +44,6 @@
 using spdy::Http2HeaderBlock;
 using spdy::kV3HighestPriority;
 using spdy::kV3LowestPriority;
-using spdy::SpdyPriority;
 using testing::_;
 using testing::AnyNumber;
 using testing::AtLeast;
@@ -320,25 +319,23 @@
 class TestMockUpdateStreamSession : public MockQuicSpdySession {
  public:
   explicit TestMockUpdateStreamSession(QuicConnection* connection)
-      : MockQuicSpdySession(connection),
-        expected_precedence_(
-            spdy::SpdyStreamPrecedence(QuicStream::kDefaultPriority)) {}
+      : MockQuicSpdySession(connection) {}
 
-  void UpdateStreamPriority(
-      QuicStreamId id, const spdy::SpdyStreamPrecedence& precedence) override {
+  void UpdateStreamPriority(QuicStreamId id,
+                            const QuicStreamPriority& new_priority) override {
     EXPECT_EQ(id, expected_stream_->id());
-    EXPECT_EQ(expected_precedence_, precedence);
-    EXPECT_EQ(expected_precedence_, expected_stream_->precedence());
+    EXPECT_EQ(expected_priority_, new_priority);
+    EXPECT_EQ(expected_priority_, expected_stream_->priority());
   }
 
   void SetExpectedStream(QuicSpdyStream* stream) { expected_stream_ = stream; }
-  void SetExpectedPriority(const spdy::SpdyStreamPrecedence& precedence) {
-    expected_precedence_ = precedence;
+  void SetExpectedPriority(const QuicStreamPriority& priority) {
+    expected_priority_ = priority;
   }
 
  private:
   QuicSpdyStream* expected_stream_;
-  spdy::SpdyStreamPrecedence expected_precedence_;
+  QuicStreamPriority expected_priority_;
 };
 
 class QuicSpdyStreamTest : public QuicTestWithParam<ParsedQuicVersion> {
@@ -1574,9 +1571,16 @@
   auto send_control_stream =
       QuicSpdySessionPeer::GetSendControlStream(session_.get());
   EXPECT_CALL(*session_, WritevData(send_control_stream->id(), _, _, _, _, _));
-  PriorityUpdateFrame priority_update{stream_->id(), "u=0"};
-  EXPECT_CALL(debug_visitor, OnPriorityUpdateFrameSent(priority_update));
-  stream_->SetPriority(spdy::SpdyStreamPrecedence(kV3HighestPriority));
+  PriorityUpdateFrame priority_update1{stream_->id(), "u=0"};
+  EXPECT_CALL(debug_visitor, OnPriorityUpdateFrameSent(priority_update1));
+  stream_->SetPriority(QuicStreamPriority{
+      kV3HighestPriority, QuicStreamPriority::kDefaultIncremental});
+
+  // Send another PRIORITY_UPDATE frame with incremental flag set to true.
+  EXPECT_CALL(*session_, WritevData(send_control_stream->id(), _, _, _, _, _));
+  PriorityUpdateFrame priority_update2{stream_->id(), "u=2, i"};
+  EXPECT_CALL(debug_visitor, OnPriorityUpdateFrameSent(priority_update2));
+  stream_->SetPriority(QuicStreamPriority{2, true});
 }
 
 TEST_P(QuicSpdyStreamTest, ChangePriorityBeforeWritingHeaders) {
@@ -1592,7 +1596,8 @@
       QuicSpdySessionPeer::GetSendControlStream(session_.get());
   EXPECT_CALL(*session_, WritevData(send_control_stream->id(), _, _, _, _, _));
 
-  stream_->SetPriority(spdy::SpdyStreamPrecedence(kV3HighestPriority));
+  stream_->SetPriority(QuicStreamPriority{
+      kV3HighestPriority, QuicStreamPriority::kDefaultIncremental});
   testing::Mock::VerifyAndClearExpectations(session_.get());
 
   // Two writes on the request stream: HEADERS frame header and payload.
@@ -1801,8 +1806,9 @@
 TEST_P(QuicSpdyStreamTest, OnPriorityFrame) {
   Initialize(kShouldProcessData);
   stream_->OnPriorityFrame(spdy::SpdyStreamPrecedence(kV3HighestPriority));
-  EXPECT_EQ(spdy::SpdyStreamPrecedence(kV3HighestPriority),
-            stream_->precedence());
+  EXPECT_EQ((QuicStreamPriority{kV3HighestPriority,
+                                QuicStreamPriority::kDefaultIncremental}),
+            stream_->priority());
 }
 
 TEST_P(QuicSpdyStreamTest, OnPriorityFrameAfterSendingData) {
@@ -1815,8 +1821,9 @@
   EXPECT_CALL(*session_, WritevData(_, 4, _, FIN, _, _));
   stream_->WriteOrBufferBody("data", true);
   stream_->OnPriorityFrame(spdy::SpdyStreamPrecedence(kV3HighestPriority));
-  EXPECT_EQ(spdy::SpdyStreamPrecedence(kV3HighestPriority),
-            stream_->precedence());
+  EXPECT_EQ((QuicStreamPriority{kV3HighestPriority,
+                                QuicStreamPriority::kDefaultIncremental}),
+            stream_->priority());
 }
 
 TEST_P(QuicSpdyStreamTest, SetPriorityBeforeUpdateStreamPriority) {
@@ -1837,11 +1844,11 @@
   // if called within UpdateStreamPriority(). This expectation is enforced in
   // TestMockUpdateStreamSession::UpdateStreamPriority().
   session->SetExpectedStream(stream);
-  session->SetExpectedPriority(spdy::SpdyStreamPrecedence(kV3HighestPriority));
-  stream->SetPriority(spdy::SpdyStreamPrecedence(kV3HighestPriority));
+  session->SetExpectedPriority(QuicStreamPriority{kV3HighestPriority});
+  stream->SetPriority(QuicStreamPriority{kV3HighestPriority});
 
-  session->SetExpectedPriority(spdy::SpdyStreamPrecedence(kV3LowestPriority));
-  stream->SetPriority(spdy::SpdyStreamPrecedence(kV3LowestPriority));
+  session->SetExpectedPriority(QuicStreamPriority{kV3LowestPriority});
+  stream->SetPriority(QuicStreamPriority{kV3LowestPriority});
 }
 
 TEST_P(QuicSpdyStreamTest, StreamWaitsForAcks) {
diff --git a/quiche/quic/core/quic_session.cc b/quiche/quic/core/quic_session.cc
index 158db55..a84f756 100644
--- a/quiche/quic/core/quic_session.cc
+++ b/quiche/quic/core/quic_session.cc
@@ -28,8 +28,6 @@
 #include "quiche/quic/platform/api/quic_stack_trace.h"
 #include "quiche/common/quiche_text_utils.h"
 
-using spdy::SpdyPriority;
-
 namespace quic {
 
 namespace {
@@ -1800,19 +1798,20 @@
 void QuicSession::OnCryptoHandshakeMessageReceived(
     const CryptoHandshakeMessage& /*message*/) {}
 
-void QuicSession::RegisterStreamPriority(
-    QuicStreamId id, bool is_static,
-    const spdy::SpdyStreamPrecedence& precedence) {
-  write_blocked_streams()->RegisterStream(id, is_static, precedence);
+void QuicSession::RegisterStreamPriority(QuicStreamId id, bool is_static,
+                                         const QuicStreamPriority& priority) {
+  write_blocked_streams()->RegisterStream(
+      id, is_static, spdy::SpdyStreamPrecedence(priority.urgency));
 }
 
 void QuicSession::UnregisterStreamPriority(QuicStreamId id, bool is_static) {
   write_blocked_streams()->UnregisterStream(id, is_static);
 }
 
-void QuicSession::UpdateStreamPriority(
-    QuicStreamId id, const spdy::SpdyStreamPrecedence& new_precedence) {
-  write_blocked_streams()->UpdateStreamPriority(id, new_precedence);
+void QuicSession::UpdateStreamPriority(QuicStreamId id,
+                                       const QuicStreamPriority& new_priority) {
+  write_blocked_streams()->UpdateStreamPriority(
+      id, spdy::SpdyStreamPrecedence(new_priority.urgency));
 }
 
 void QuicSession::ActivateStream(std::unique_ptr<QuicStream> stream) {
@@ -2031,11 +2030,11 @@
   }
 }
 
-bool QuicSession::MaybeSetStreamPriority(
-    QuicStreamId stream_id, const spdy::SpdyStreamPrecedence& precedence) {
+bool QuicSession::MaybeSetStreamPriority(QuicStreamId stream_id,
+                                         const QuicStreamPriority& priority) {
   auto active_stream = stream_map_.find(stream_id);
   if (active_stream != stream_map_.end()) {
-    active_stream->second->SetPriority(precedence);
+    active_stream->second->SetPriority(priority);
     return true;
   }
 
diff --git a/quiche/quic/core/quic_session.h b/quiche/quic/core/quic_session.h
index 07711ac..2117c8b 100644
--- a/quiche/quic/core/quic_session.h
+++ b/quiche/quic/core/quic_session.h
@@ -35,6 +35,7 @@
 #include "quiche/quic/core/quic_path_validator.h"
 #include "quiche/quic/core/quic_stream.h"
 #include "quiche/quic/core/quic_stream_frame_data_producer.h"
+#include "quiche/quic/core/quic_stream_priority.h"
 #include "quiche/quic/core/quic_types.h"
 #include "quiche/quic/core/quic_write_blocked_list.h"
 #include "quiche/quic/core/session_notifier_interface.h"
@@ -326,15 +327,13 @@
                      QuicIetfTransportErrorCodes ietf_error,
                      std::string error_details) override;
   // Sets priority in the write blocked list.
-  void RegisterStreamPriority(
-      QuicStreamId id, bool is_static,
-      const spdy::SpdyStreamPrecedence& precedence) override;
+  void RegisterStreamPriority(QuicStreamId id, bool is_static,
+                              const QuicStreamPriority& priority) override;
   // Clears priority from the write blocked list.
   void UnregisterStreamPriority(QuicStreamId id, bool is_static) override;
   // Updates priority on the write blocked list.
-  void UpdateStreamPriority(
-      QuicStreamId id,
-      const spdy::SpdyStreamPrecedence& new_precedence) override;
+  void UpdateStreamPriority(QuicStreamId id,
+                            const QuicStreamPriority& new_priority) override;
 
   // Called by streams when they want to write data to the peer.
   // Returns a pair with the number of bytes consumed from data, and a boolean
@@ -789,7 +788,7 @@
 
   // Call SetPriority() on stream id |id| and return true if stream is active.
   bool MaybeSetStreamPriority(QuicStreamId stream_id,
-                              const spdy::SpdyStreamPrecedence& precedence);
+                              const QuicStreamPriority& priority);
 
   void SetLossDetectionTuner(
       std::unique_ptr<LossDetectionTunerInterface> tuner) {
diff --git a/quiche/quic/core/quic_session_test.cc b/quiche/quic/core/quic_session_test.cc
index d663cbd..4118657 100644
--- a/quiche/quic/core/quic_session_test.cc
+++ b/quiche/quic/core/quic_session_test.cc
@@ -1063,7 +1063,8 @@
   // Now let stream 4 do the 2nd of its 3 writes, but add a block for a high
   // priority stream 6.  4 should be preempted.  6 will write but *not* block so
   // will cede back to 4.
-  stream6->SetPriority(spdy::SpdyStreamPrecedence(kV3HighestPriority));
+  stream6->SetPriority(QuicStreamPriority{
+      kV3HighestPriority, QuicStreamPriority::kDefaultIncremental});
   EXPECT_CALL(*stream4, OnCanWrite())
       .WillOnce(Invoke([this, stream4, stream6]() {
         session_.SendLargeFakeData(stream4, 6000);
diff --git a/quiche/quic/core/quic_stream.cc b/quiche/quic/core/quic_stream.cc
index 9a121cb..3d02d1c 100644
--- a/quiche/quic/core/quic_stream.cc
+++ b/quiche/quic/core/quic_stream.cc
@@ -13,7 +13,6 @@
 #include "quiche/quic/core/quic_error_codes.h"
 #include "quiche/quic/core/quic_flow_controller.h"
 #include "quiche/quic/core/quic_session.h"
-#include "quiche/quic/core/quic_stream_priority.h"
 #include "quiche/quic/core/quic_types.h"
 #include "quiche/quic/core/quic_utils.h"
 #include "quiche/quic/core/quic_versions.h"
@@ -340,7 +339,7 @@
       id_(id),
       session_(session),
       stream_delegate_(session),
-      precedence_(CalculateDefaultPriority(session)),
+      priority_(CalculateDefaultPriority(session->transport_version())),
       stream_bytes_read_(stream_bytes_read),
       stream_error_(QuicResetStreamError::NoError()),
       connection_error_(QUIC_NO_ERROR),
@@ -382,7 +381,7 @@
     CloseWriteSide();
   }
   if (type_ != CRYPTO) {
-    stream_delegate_->RegisterStreamPriority(id, is_static_, precedence_);
+    stream_delegate_->RegisterStreamPriority(id, is_static_, priority_);
   }
 }
 
@@ -633,16 +632,14 @@
   stream_delegate_->OnStreamError(error, ietf_error, details);
 }
 
-const spdy::SpdyStreamPrecedence& QuicStream::precedence() const {
-  return precedence_;
-}
+const QuicStreamPriority& QuicStream::priority() const { return priority_; }
 
-void QuicStream::SetPriority(const spdy::SpdyStreamPrecedence& precedence) {
-  precedence_ = precedence;
+void QuicStream::SetPriority(const QuicStreamPriority& priority) {
+  priority_ = priority;
 
   MaybeSendPriorityUpdateFrame();
 
-  stream_delegate_->UpdateStreamPriority(id(), precedence);
+  stream_delegate_->UpdateStreamPriority(id(), priority);
 }
 
 void QuicStream::WriteOrBufferData(
@@ -1425,12 +1422,15 @@
 }
 
 // static
-spdy::SpdyStreamPrecedence QuicStream::CalculateDefaultPriority(
-    const QuicSession* session) {
-  return spdy::SpdyStreamPrecedence(
-      VersionUsesHttp3(session->transport_version())
-          ? QuicStreamPriority::kDefaultUrgency
-          : QuicStream::kDefaultPriority);
+QuicStreamPriority QuicStream::CalculateDefaultPriority(
+    QuicTransportVersion version) {
+  if (VersionUsesHttp3(version)) {
+    return QuicStreamPriority{QuicStreamPriority::kDefaultUrgency,
+                              QuicStreamPriority::kDefaultIncremental};
+  } else {
+    return QuicStreamPriority{QuicStream::kDefaultPriority,
+                              QuicStreamPriority::kDefaultIncremental};
+  }
 }
 
 absl::optional<QuicByteCount> QuicStream::GetSendWindow() const {
diff --git a/quiche/quic/core/quic_stream.h b/quiche/quic/core/quic_stream.h
index f8aff9a..77213a8 100644
--- a/quiche/quic/core/quic_stream.h
+++ b/quiche/quic/core/quic_stream.h
@@ -29,6 +29,7 @@
 #include "quiche/quic/core/quic_error_codes.h"
 #include "quiche/quic/core/quic_flow_controller.h"
 #include "quiche/quic/core/quic_packets.h"
+#include "quiche/quic/core/quic_stream_priority.h"
 #include "quiche/quic/core/quic_stream_send_buffer.h"
 #include "quiche/quic/core/quic_stream_sequencer.h"
 #include "quiche/quic/core/quic_types.h"
@@ -206,7 +207,7 @@
   virtual void OnConnectionClosed(QuicErrorCode error,
                                   ConnectionCloseSource source);
 
-  const spdy::SpdyStreamPrecedence& precedence() const;
+  const QuicStreamPriority& priority() const;
 
   // Send PRIORITY_UPDATE frame if application protocol supports it.
   virtual void MaybeSendPriorityUpdateFrame() {}
@@ -216,7 +217,7 @@
   // PRIORITY_UPDATE frame is received.  This calls
   // MaybeSendPriorityUpdateFrame(), which for a client stream might send a
   // PRIORITY_UPDATE frame.
-  void SetPriority(const spdy::SpdyStreamPrecedence& precedence);
+  void SetPriority(const QuicStreamPriority& priority);
 
   // Returns true if this stream is still waiting for acks of sent data.
   // This will return false if all data has been acked, or if the stream
@@ -388,8 +389,8 @@
 
   bool was_draining() const { return was_draining_; }
 
-  static spdy::SpdyStreamPrecedence CalculateDefaultPriority(
-      const QuicSession* session);
+  static QuicStreamPriority CalculateDefaultPriority(
+      QuicTransportVersion version);
 
   QuicTime creation_time() const { return creation_time_; }
 
@@ -525,8 +526,8 @@
   // TODO(b/136274541): Remove session pointer from streams.
   QuicSession* session_;
   StreamDelegateInterface* stream_delegate_;
-  // The precedence of the stream, once parsed.
-  spdy::SpdyStreamPrecedence precedence_;
+  // The priority of the stream, once parsed.
+  QuicStreamPriority priority_;
   // Bytes read refers to payload bytes only: they do not include framing,
   // encryption overhead etc.
   uint64_t stream_bytes_read_;
diff --git a/quiche/quic/core/stream_delegate_interface.h b/quiche/quic/core/stream_delegate_interface.h
index f445fe8..b6db350 100644
--- a/quiche/quic/core/stream_delegate_interface.h
+++ b/quiche/quic/core/stream_delegate_interface.h
@@ -8,8 +8,8 @@
 #include <cstddef>
 
 #include "absl/types/optional.h"
+#include "quiche/quic/core/quic_stream_priority.h"
 #include "quiche/quic/core/quic_types.h"
-#include "quiche/spdy/core/spdy_protocol.h"
 
 namespace quic {
 
@@ -41,14 +41,13 @@
                                 QuicStreamOffset offset,
                                 TransmissionType type) = 0;
   // Called on stream creation.
-  virtual void RegisterStreamPriority(
-      QuicStreamId id, bool is_static,
-      const spdy::SpdyStreamPrecedence& precedence) = 0;
+  virtual void RegisterStreamPriority(QuicStreamId id, bool is_static,
+                                      const QuicStreamPriority& priority) = 0;
   // Called on stream destruction to clear priority.
   virtual void UnregisterStreamPriority(QuicStreamId id, bool is_static) = 0;
   // Called by the stream on SetPriority to update priority.
-  virtual void UpdateStreamPriority(
-      QuicStreamId id, const spdy::SpdyStreamPrecedence& new_precedence) = 0;
+  virtual void UpdateStreamPriority(QuicStreamId id,
+                                    const QuicStreamPriority& new_priority) = 0;
 };
 
 }  // namespace quic
diff --git a/quiche/quic/test_tools/quic_test_client.cc b/quiche/quic/test_tools/quic_test_client.cc
index f711036..17e1d73 100644
--- a/quiche/quic/test_tools/quic_test_client.cc
+++ b/quiche/quic/test_tools/quic_test_client.cc
@@ -18,6 +18,7 @@
 #include "quiche/quic/core/quic_default_clock.h"
 #include "quiche/quic/core/quic_packet_writer_wrapper.h"
 #include "quiche/quic/core/quic_server_id.h"
+#include "quiche/quic/core/quic_stream_priority.h"
 #include "quiche/quic/core/quic_utils.h"
 #include "quiche/quic/platform/api/quic_flags.h"
 #include "quiche/quic/platform/api/quic_logging.h"
@@ -543,7 +544,7 @@
     SetLatestCreatedStream(client_->CreateClientStream());
     if (latest_created_stream_) {
       latest_created_stream_->SetPriority(
-          spdy::SpdyStreamPrecedence(priority_));
+          QuicStreamPriority{priority_, /* incremental = */ false});
     }
   }
 
diff --git a/quiche/quic/tools/quic_simple_server_session.cc b/quiche/quic/tools/quic_simple_server_session.cc
index 15e43b9..a8ac5f0 100644
--- a/quiche/quic/tools/quic_simple_server_session.cc
+++ b/quiche/quic/tools/quic_simple_server_session.cc
@@ -10,6 +10,7 @@
 #include "quiche/quic/core/http/quic_server_initiated_spdy_stream.h"
 #include "quiche/quic/core/http/quic_spdy_session.h"
 #include "quiche/quic/core/quic_connection.h"
+#include "quiche/quic/core/quic_stream_priority.h"
 #include "quiche/quic/core/quic_types.h"
 #include "quiche/quic/core/quic_utils.h"
 #include "quiche/quic/platform/api/quic_flags.h"
@@ -195,7 +196,9 @@
     QUICHE_DCHECK_EQ(promised_info.stream_id, promised_stream->id());
     QUIC_DLOG(INFO) << "created server push stream " << promised_stream->id();
 
-    promised_stream->SetPriority(promised_info.precedence);
+    promised_stream->SetPriority(
+        QuicStreamPriority{promised_info.precedence.spdy3_priority(),
+                           QuicStreamPriority::kDefaultIncremental});
 
     spdy::Http2HeaderBlock request_headers(
         std::move(promised_info.request_headers));
diff --git a/quiche/quic/tools/quic_simple_server_session_test.cc b/quiche/quic/tools/quic_simple_server_session_test.cc
index d1db8c9..d6eb67f 100644
--- a/quiche/quic/tools/quic_simple_server_session_test.cc
+++ b/quiche/quic/tools/quic_simple_server_session_test.cc
@@ -503,8 +503,7 @@
   if (!VersionUsesHttp3(transport_version())) {
     session_->RegisterStreamPriority(
         QuicUtils::GetHeadersStreamId(transport_version()),
-        /*is_static=*/true,
-        spdy::SpdyStreamPrecedence(QuicStream::kDefaultPriority));
+        /*is_static=*/true, QuicStreamPriority());
   }
 
   // Create push streams till reaching the upper limit of allowed open streams.